mirror of
https://github.com/zed-industries/zed.git
synced 2024-09-19 18:41:56 +03:00
Rescan worktree on scan exclusions settings change
This commit is contained in:
parent
1612c90052
commit
9373d38434
@ -11,7 +11,6 @@ pub struct ProjectSettings {
|
|||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub git: GitSettings,
|
pub git: GitSettings,
|
||||||
// TODO kb better names and docs and tests
|
// TODO kb better names and docs and tests
|
||||||
// TODO kb how to react on their changes?
|
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub scan_exclude_files: Vec<String>,
|
pub scan_exclude_files: Vec<String>,
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,10 @@ use futures::{
|
|||||||
};
|
};
|
||||||
use fuzzy::CharBag;
|
use fuzzy::CharBag;
|
||||||
use git::{DOT_GIT, GITIGNORE};
|
use git::{DOT_GIT, GITIGNORE};
|
||||||
use gpui::{executor, AppContext, AsyncAppContext, Entity, ModelContext, ModelHandle, Task};
|
use gpui::{
|
||||||
|
executor, AppContext, AsyncAppContext, Entity, ModelContext, ModelHandle, Subscription, Task,
|
||||||
|
};
|
||||||
|
use itertools::Itertools;
|
||||||
use language::{
|
use language::{
|
||||||
proto::{
|
proto::{
|
||||||
deserialize_fingerprint, deserialize_version, serialize_fingerprint, serialize_line_ending,
|
deserialize_fingerprint, deserialize_version, serialize_fingerprint, serialize_line_ending,
|
||||||
@ -37,6 +40,7 @@ use postage::{
|
|||||||
prelude::{Sink as _, Stream as _},
|
prelude::{Sink as _, Stream as _},
|
||||||
watch,
|
watch,
|
||||||
};
|
};
|
||||||
|
use settings::SettingsStore;
|
||||||
use smol::channel::{self, Sender};
|
use smol::channel::{self, Sender};
|
||||||
use std::{
|
use std::{
|
||||||
any::Any,
|
any::Any,
|
||||||
@ -74,7 +78,8 @@ pub struct LocalWorktree {
|
|||||||
scan_requests_tx: channel::Sender<ScanRequest>,
|
scan_requests_tx: channel::Sender<ScanRequest>,
|
||||||
path_prefixes_to_scan_tx: channel::Sender<Arc<Path>>,
|
path_prefixes_to_scan_tx: channel::Sender<Arc<Path>>,
|
||||||
is_scanning: (watch::Sender<bool>, watch::Receiver<bool>),
|
is_scanning: (watch::Sender<bool>, watch::Receiver<bool>),
|
||||||
_background_scanner_task: Task<()>,
|
_settings_subscription: Subscription,
|
||||||
|
_background_scanner_tasks: Vec<Task<()>>,
|
||||||
share: Option<ShareState>,
|
share: Option<ShareState>,
|
||||||
diagnostics: HashMap<
|
diagnostics: HashMap<
|
||||||
Arc<Path>,
|
Arc<Path>,
|
||||||
@ -304,30 +309,55 @@ impl Worktree {
|
|||||||
.await
|
.await
|
||||||
.context("failed to stat worktree path")?;
|
.context("failed to stat worktree path")?;
|
||||||
|
|
||||||
|
let closure_fs = Arc::clone(&fs);
|
||||||
|
let closure_next_entry_id = Arc::clone(&next_entry_id);
|
||||||
|
let closure_abs_path = abs_path.to_path_buf();
|
||||||
Ok(cx.add_model(move |cx: &mut ModelContext<Worktree>| {
|
Ok(cx.add_model(move |cx: &mut ModelContext<Worktree>| {
|
||||||
|
let settings_subscription = cx.observe_global::<SettingsStore, _>(move |this, cx| {
|
||||||
|
if let Self::Local(this) = this {
|
||||||
|
let new_scan_exclude_files =
|
||||||
|
scan_exclude_files(settings::get::<ProjectSettings>(cx));
|
||||||
|
if new_scan_exclude_files != this.snapshot.scan_exclude_files {
|
||||||
|
this.snapshot.scan_exclude_files = new_scan_exclude_files;
|
||||||
|
log::info!(
|
||||||
|
"Re-scanning due to new scan exclude files: {:?}",
|
||||||
|
this.snapshot
|
||||||
|
.scan_exclude_files
|
||||||
|
.iter()
|
||||||
|
.map(ToString::to_string)
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
);
|
||||||
|
|
||||||
|
let (scan_requests_tx, scan_requests_rx) = channel::unbounded();
|
||||||
|
let (path_prefixes_to_scan_tx, path_prefixes_to_scan_rx) =
|
||||||
|
channel::unbounded();
|
||||||
|
this.scan_requests_tx = scan_requests_tx;
|
||||||
|
this.path_prefixes_to_scan_tx = path_prefixes_to_scan_tx;
|
||||||
|
this._background_scanner_tasks = start_background_scan_tasks(
|
||||||
|
&closure_abs_path,
|
||||||
|
this.snapshot(),
|
||||||
|
scan_requests_rx,
|
||||||
|
path_prefixes_to_scan_rx,
|
||||||
|
Arc::clone(&closure_next_entry_id),
|
||||||
|
Arc::clone(&closure_fs),
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
this.is_scanning = watch::channel_with(true);
|
||||||
|
// TODO kb change more state? will this even work now?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
let root_name = abs_path
|
let root_name = abs_path
|
||||||
.file_name()
|
.file_name()
|
||||||
.map_or(String::new(), |f| f.to_string_lossy().to_string());
|
.map_or(String::new(), |f| f.to_string_lossy().to_string());
|
||||||
let project_settings = settings::get::<ProjectSettings>(cx);
|
|
||||||
let scan_exclude_files = project_settings.scan_exclude_files.iter()
|
|
||||||
.filter_map(|pattern| {
|
|
||||||
PathMatcher::new(pattern)
|
|
||||||
.map(Some)
|
|
||||||
.unwrap_or_else(|e| {
|
|
||||||
log::error!(
|
|
||||||
"Skipping pattern {pattern} in `scan_exclude_files` project settings due to parsing error: {e:#}"
|
|
||||||
);
|
|
||||||
None
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
let mut snapshot = LocalSnapshot {
|
let mut snapshot = LocalSnapshot {
|
||||||
scan_exclude_files,
|
scan_exclude_files: scan_exclude_files(settings::get::<ProjectSettings>(cx)),
|
||||||
ignores_by_parent_abs_path: Default::default(),
|
ignores_by_parent_abs_path: Default::default(),
|
||||||
git_repositories: Default::default(),
|
git_repositories: Default::default(),
|
||||||
snapshot: Snapshot {
|
snapshot: Snapshot {
|
||||||
id: WorktreeId::from_usize(cx.model_id()),
|
id: WorktreeId::from_usize(cx.model_id()),
|
||||||
abs_path: abs_path.clone(),
|
abs_path: abs_path.to_path_buf().into(),
|
||||||
root_name: root_name.clone(),
|
root_name: root_name.clone(),
|
||||||
root_char_bag: root_name.chars().map(|c| c.to_ascii_lowercase()).collect(),
|
root_char_bag: root_name.chars().map(|c| c.to_ascii_lowercase()).collect(),
|
||||||
entries_by_path: Default::default(),
|
entries_by_path: Default::default(),
|
||||||
@ -352,60 +382,23 @@ impl Worktree {
|
|||||||
|
|
||||||
let (scan_requests_tx, scan_requests_rx) = channel::unbounded();
|
let (scan_requests_tx, scan_requests_rx) = channel::unbounded();
|
||||||
let (path_prefixes_to_scan_tx, path_prefixes_to_scan_rx) = channel::unbounded();
|
let (path_prefixes_to_scan_tx, path_prefixes_to_scan_rx) = channel::unbounded();
|
||||||
let (scan_states_tx, mut scan_states_rx) = mpsc::unbounded();
|
let task_snapshot = snapshot.clone();
|
||||||
|
|
||||||
cx.spawn_weak(|this, mut cx| async move {
|
|
||||||
while let Some((state, this)) = scan_states_rx.next().await.zip(this.upgrade(&cx)) {
|
|
||||||
this.update(&mut cx, |this, cx| {
|
|
||||||
let this = this.as_local_mut().unwrap();
|
|
||||||
match state {
|
|
||||||
ScanState::Started => {
|
|
||||||
*this.is_scanning.0.borrow_mut() = true;
|
|
||||||
}
|
|
||||||
ScanState::Updated {
|
|
||||||
snapshot,
|
|
||||||
changes,
|
|
||||||
barrier,
|
|
||||||
scanning,
|
|
||||||
} => {
|
|
||||||
*this.is_scanning.0.borrow_mut() = scanning;
|
|
||||||
this.set_snapshot(snapshot, changes, cx);
|
|
||||||
drop(barrier);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cx.notify();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.detach();
|
|
||||||
|
|
||||||
let background_scanner_task = cx.background().spawn({
|
|
||||||
let fs = fs.clone();
|
|
||||||
let snapshot = snapshot.clone();
|
|
||||||
let background = cx.background().clone();
|
|
||||||
async move {
|
|
||||||
let events = fs.watch(&abs_path, Duration::from_millis(100)).await;
|
|
||||||
BackgroundScanner::new(
|
|
||||||
snapshot,
|
|
||||||
next_entry_id,
|
|
||||||
fs,
|
|
||||||
scan_states_tx,
|
|
||||||
background,
|
|
||||||
scan_requests_rx,
|
|
||||||
path_prefixes_to_scan_rx,
|
|
||||||
)
|
|
||||||
.run(events)
|
|
||||||
.await;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Worktree::Local(LocalWorktree {
|
Worktree::Local(LocalWorktree {
|
||||||
snapshot,
|
snapshot,
|
||||||
is_scanning: watch::channel_with(true),
|
is_scanning: watch::channel_with(true),
|
||||||
share: None,
|
share: None,
|
||||||
scan_requests_tx,
|
scan_requests_tx,
|
||||||
path_prefixes_to_scan_tx,
|
path_prefixes_to_scan_tx,
|
||||||
_background_scanner_task: background_scanner_task,
|
_settings_subscription: settings_subscription,
|
||||||
|
_background_scanner_tasks: start_background_scan_tasks(
|
||||||
|
&abs_path,
|
||||||
|
task_snapshot,
|
||||||
|
scan_requests_rx,
|
||||||
|
path_prefixes_to_scan_rx,
|
||||||
|
Arc::clone(&next_entry_id),
|
||||||
|
Arc::clone(&fs),
|
||||||
|
cx,
|
||||||
|
),
|
||||||
diagnostics: Default::default(),
|
diagnostics: Default::default(),
|
||||||
diagnostic_summaries: Default::default(),
|
diagnostic_summaries: Default::default(),
|
||||||
client,
|
client,
|
||||||
@ -602,6 +595,76 @@ impl Worktree {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn start_background_scan_tasks(
|
||||||
|
abs_path: &Path,
|
||||||
|
snapshot: LocalSnapshot,
|
||||||
|
scan_requests_rx: channel::Receiver<ScanRequest>,
|
||||||
|
path_prefixes_to_scan_rx: channel::Receiver<Arc<Path>>,
|
||||||
|
next_entry_id: Arc<AtomicUsize>,
|
||||||
|
fs: Arc<dyn Fs>,
|
||||||
|
cx: &mut ModelContext<'_, Worktree>,
|
||||||
|
) -> Vec<Task<()>> {
|
||||||
|
let (scan_states_tx, mut scan_states_rx) = mpsc::unbounded();
|
||||||
|
let background_scanner = cx.background().spawn({
|
||||||
|
let abs_path = abs_path.to_path_buf();
|
||||||
|
let background = cx.background().clone();
|
||||||
|
async move {
|
||||||
|
let events = fs.watch(&abs_path, Duration::from_millis(100)).await;
|
||||||
|
BackgroundScanner::new(
|
||||||
|
snapshot,
|
||||||
|
next_entry_id,
|
||||||
|
fs,
|
||||||
|
scan_states_tx,
|
||||||
|
background,
|
||||||
|
scan_requests_rx,
|
||||||
|
path_prefixes_to_scan_rx,
|
||||||
|
)
|
||||||
|
.run(events)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let scan_state_updater = cx.spawn_weak(|this, mut cx| async move {
|
||||||
|
while let Some((state, this)) = scan_states_rx.next().await.zip(this.upgrade(&cx)) {
|
||||||
|
this.update(&mut cx, |this, cx| {
|
||||||
|
let this = this.as_local_mut().unwrap();
|
||||||
|
match state {
|
||||||
|
ScanState::Started => {
|
||||||
|
*this.is_scanning.0.borrow_mut() = true;
|
||||||
|
}
|
||||||
|
ScanState::Updated {
|
||||||
|
snapshot,
|
||||||
|
changes,
|
||||||
|
barrier,
|
||||||
|
scanning,
|
||||||
|
} => {
|
||||||
|
*this.is_scanning.0.borrow_mut() = scanning;
|
||||||
|
this.set_snapshot(snapshot, changes, cx);
|
||||||
|
drop(barrier);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cx.notify();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
vec![background_scanner, scan_state_updater]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn scan_exclude_files(project_settings: &ProjectSettings) -> Vec<PathMatcher> {
|
||||||
|
project_settings.scan_exclude_files.iter()
|
||||||
|
.sorted()
|
||||||
|
.filter_map(|pattern| {
|
||||||
|
PathMatcher::new(pattern)
|
||||||
|
.map(Some)
|
||||||
|
.unwrap_or_else(|e| {
|
||||||
|
log::error!(
|
||||||
|
"Skipping pattern {pattern} in `scan_exclude_files` project settings due to parsing error: {e:#}"
|
||||||
|
);
|
||||||
|
None
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
impl LocalWorktree {
|
impl LocalWorktree {
|
||||||
pub fn contains_abs_path(&self, path: &Path) -> bool {
|
pub fn contains_abs_path(&self, path: &Path) -> bool {
|
||||||
path.starts_with(&self.abs_path)
|
path.starts_with(&self.abs_path)
|
||||||
|
@ -202,6 +202,14 @@ impl std::fmt::Display for PathMatcher {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl PartialEq for PathMatcher {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.maybe_path.eq(&other.maybe_path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Eq for PathMatcher {}
|
||||||
|
|
||||||
impl PathMatcher {
|
impl PathMatcher {
|
||||||
pub fn new(maybe_glob: &str) -> Result<Self, globset::Error> {
|
pub fn new(maybe_glob: &str) -> Result<Self, globset::Error> {
|
||||||
Ok(PathMatcher {
|
Ok(PathMatcher {
|
||||||
|
Loading…
Reference in New Issue
Block a user