mirror of
https://github.com/zed-industries/zed.git
synced 2024-10-27 00:41:37 +00:00
Notify language servers of FS changes
This commit is contained in:
parent
9837a6e288
commit
61172c8478
4 changed files with 147 additions and 15 deletions
|
@ -319,6 +319,9 @@ impl LanguageServer {
|
||||||
capabilities: ClientCapabilities {
|
capabilities: ClientCapabilities {
|
||||||
workspace: Some(WorkspaceClientCapabilities {
|
workspace: Some(WorkspaceClientCapabilities {
|
||||||
configuration: Some(true),
|
configuration: Some(true),
|
||||||
|
did_change_watched_files: Some(DynamicRegistrationClientCapabilities {
|
||||||
|
dynamic_registration: Some(true),
|
||||||
|
}),
|
||||||
did_change_configuration: Some(DynamicRegistrationClientCapabilities {
|
did_change_configuration: Some(DynamicRegistrationClientCapabilities {
|
||||||
dynamic_registration: Some(true),
|
dynamic_registration: Some(true),
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -4465,7 +4465,10 @@ impl Project {
|
||||||
cx.observe(worktree, |_, _, cx| cx.notify()).detach();
|
cx.observe(worktree, |_, _, cx| cx.notify()).detach();
|
||||||
if worktree.read(cx).is_local() {
|
if worktree.read(cx).is_local() {
|
||||||
cx.subscribe(worktree, |this, worktree, event, cx| match event {
|
cx.subscribe(worktree, |this, worktree, event, cx| match event {
|
||||||
worktree::Event::UpdatedEntries => this.update_local_worktree_buffers(worktree, cx),
|
worktree::Event::UpdatedEntries(changes) => {
|
||||||
|
this.update_local_worktree_buffers(&worktree, cx);
|
||||||
|
this.update_local_worktree_language_servers(&worktree, changes, cx);
|
||||||
|
}
|
||||||
worktree::Event::UpdatedGitRepositories(updated_repos) => {
|
worktree::Event::UpdatedGitRepositories(updated_repos) => {
|
||||||
this.update_local_worktree_buffers_git_repos(worktree, updated_repos, cx)
|
this.update_local_worktree_buffers_git_repos(worktree, updated_repos, cx)
|
||||||
}
|
}
|
||||||
|
@ -4496,7 +4499,7 @@ impl Project {
|
||||||
|
|
||||||
fn update_local_worktree_buffers(
|
fn update_local_worktree_buffers(
|
||||||
&mut self,
|
&mut self,
|
||||||
worktree_handle: ModelHandle<Worktree>,
|
worktree_handle: &ModelHandle<Worktree>,
|
||||||
cx: &mut ModelContext<Self>,
|
cx: &mut ModelContext<Self>,
|
||||||
) {
|
) {
|
||||||
let snapshot = worktree_handle.read(cx).snapshot();
|
let snapshot = worktree_handle.read(cx).snapshot();
|
||||||
|
@ -4506,7 +4509,7 @@ impl Project {
|
||||||
if let Some(buffer) = buffer.upgrade(cx) {
|
if let Some(buffer) = buffer.upgrade(cx) {
|
||||||
buffer.update(cx, |buffer, cx| {
|
buffer.update(cx, |buffer, cx| {
|
||||||
if let Some(old_file) = File::from_dyn(buffer.file()) {
|
if let Some(old_file) = File::from_dyn(buffer.file()) {
|
||||||
if old_file.worktree != worktree_handle {
|
if old_file.worktree != *worktree_handle {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4578,6 +4581,42 @@ impl Project {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn update_local_worktree_language_servers(
|
||||||
|
&mut self,
|
||||||
|
worktree_handle: &ModelHandle<Worktree>,
|
||||||
|
changes: &HashMap<Arc<Path>, PathChange>,
|
||||||
|
cx: &mut ModelContext<Self>,
|
||||||
|
) {
|
||||||
|
let worktree_id = worktree_handle.read(cx).id();
|
||||||
|
let abs_path = worktree_handle.read(cx).abs_path();
|
||||||
|
for ((server_worktree_id, _), server_id) in &self.language_server_ids {
|
||||||
|
if *server_worktree_id == worktree_id {
|
||||||
|
if let Some(server) = self.language_servers.get(server_id) {
|
||||||
|
if let LanguageServerState::Running { server, .. } = server {
|
||||||
|
server
|
||||||
|
.notify::<lsp::notification::DidChangeWatchedFiles>(
|
||||||
|
lsp::DidChangeWatchedFilesParams {
|
||||||
|
changes: changes
|
||||||
|
.iter()
|
||||||
|
.map(|(path, change)| lsp::FileEvent {
|
||||||
|
uri: lsp::Url::from_file_path(abs_path.join(path))
|
||||||
|
.unwrap(),
|
||||||
|
typ: match change {
|
||||||
|
PathChange::Added => lsp::FileChangeType::CREATED,
|
||||||
|
PathChange::Removed => lsp::FileChangeType::DELETED,
|
||||||
|
PathChange::Updated => lsp::FileChangeType::CHANGED,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.log_err();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn update_local_worktree_buffers_git_repos(
|
fn update_local_worktree_buffers_git_repos(
|
||||||
&mut self,
|
&mut self,
|
||||||
worktree: ModelHandle<Worktree>,
|
worktree: ModelHandle<Worktree>,
|
||||||
|
|
|
@ -509,14 +509,14 @@ async fn test_reporting_fs_changes_to_language_servers(cx: &mut gpui::TestAppCon
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
&*file_changes.lock(),
|
&*file_changes.lock(),
|
||||||
&[
|
&[
|
||||||
|
lsp::FileEvent {
|
||||||
|
uri: lsp::Url::from_file_path("/the-root/b.rs").unwrap(),
|
||||||
|
typ: lsp::FileChangeType::DELETED,
|
||||||
|
},
|
||||||
lsp::FileEvent {
|
lsp::FileEvent {
|
||||||
uri: lsp::Url::from_file_path("/the-root/c.rs").unwrap(),
|
uri: lsp::Url::from_file_path("/the-root/c.rs").unwrap(),
|
||||||
typ: lsp::FileChangeType::CREATED,
|
typ: lsp::FileChangeType::CREATED,
|
||||||
},
|
},
|
||||||
lsp::FileEvent {
|
|
||||||
uri: lsp::Url::from_file_path("/the-root/b.rs").unwrap(),
|
|
||||||
typ: lsp::FileChangeType::DELETED,
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,6 @@ use postage::{
|
||||||
prelude::{Sink as _, Stream as _},
|
prelude::{Sink as _, Stream as _},
|
||||||
watch,
|
watch,
|
||||||
};
|
};
|
||||||
|
|
||||||
use smol::channel::{self, Sender};
|
use smol::channel::{self, Sender};
|
||||||
use std::{
|
use std::{
|
||||||
any::Any,
|
any::Any,
|
||||||
|
@ -65,6 +64,7 @@ pub enum Worktree {
|
||||||
pub struct LocalWorktree {
|
pub struct LocalWorktree {
|
||||||
snapshot: LocalSnapshot,
|
snapshot: LocalSnapshot,
|
||||||
background_snapshot: Arc<Mutex<LocalSnapshot>>,
|
background_snapshot: Arc<Mutex<LocalSnapshot>>,
|
||||||
|
background_changes: Arc<Mutex<HashMap<Arc<Path>, PathChange>>>,
|
||||||
last_scan_state_rx: watch::Receiver<ScanState>,
|
last_scan_state_rx: watch::Receiver<ScanState>,
|
||||||
_background_scanner_task: Option<Task<()>>,
|
_background_scanner_task: Option<Task<()>>,
|
||||||
poll_task: Option<Task<()>>,
|
poll_task: Option<Task<()>>,
|
||||||
|
@ -175,7 +175,7 @@ struct ShareState {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum Event {
|
pub enum Event {
|
||||||
UpdatedEntries,
|
UpdatedEntries(HashMap<Arc<Path>, PathChange>),
|
||||||
UpdatedGitRepositories(Vec<GitRepositoryEntry>),
|
UpdatedGitRepositories(Vec<GitRepositoryEntry>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -198,11 +198,17 @@ impl Worktree {
|
||||||
let tree = tree.as_local_mut().unwrap();
|
let tree = tree.as_local_mut().unwrap();
|
||||||
let abs_path = tree.abs_path().clone();
|
let abs_path = tree.abs_path().clone();
|
||||||
let background_snapshot = tree.background_snapshot.clone();
|
let background_snapshot = tree.background_snapshot.clone();
|
||||||
|
let background_changes = tree.background_changes.clone();
|
||||||
let background = cx.background().clone();
|
let background = cx.background().clone();
|
||||||
tree._background_scanner_task = Some(cx.background().spawn(async move {
|
tree._background_scanner_task = Some(cx.background().spawn(async move {
|
||||||
let events = fs.watch(&abs_path, Duration::from_millis(100)).await;
|
let events = fs.watch(&abs_path, Duration::from_millis(100)).await;
|
||||||
let scanner =
|
let scanner = BackgroundScanner::new(
|
||||||
BackgroundScanner::new(background_snapshot, scan_states_tx, fs, background);
|
background_snapshot,
|
||||||
|
background_changes,
|
||||||
|
scan_states_tx,
|
||||||
|
fs,
|
||||||
|
background,
|
||||||
|
);
|
||||||
scanner.run(events).await;
|
scanner.run(events).await;
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
@ -451,6 +457,7 @@ impl LocalWorktree {
|
||||||
let tree = Self {
|
let tree = Self {
|
||||||
snapshot: snapshot.clone(),
|
snapshot: snapshot.clone(),
|
||||||
background_snapshot: Arc::new(Mutex::new(snapshot)),
|
background_snapshot: Arc::new(Mutex::new(snapshot)),
|
||||||
|
background_changes: Arc::new(Mutex::new(HashMap::default())),
|
||||||
last_scan_state_rx,
|
last_scan_state_rx,
|
||||||
_background_scanner_task: None,
|
_background_scanner_task: None,
|
||||||
share: None,
|
share: None,
|
||||||
|
@ -563,6 +570,7 @@ impl LocalWorktree {
|
||||||
match self.scan_state() {
|
match self.scan_state() {
|
||||||
ScanState::Idle => {
|
ScanState::Idle => {
|
||||||
let new_snapshot = self.background_snapshot.lock().clone();
|
let new_snapshot = self.background_snapshot.lock().clone();
|
||||||
|
let changes = mem::take(&mut *self.background_changes.lock());
|
||||||
let updated_repos = Self::changed_repos(
|
let updated_repos = Self::changed_repos(
|
||||||
&self.snapshot.git_repositories,
|
&self.snapshot.git_repositories,
|
||||||
&new_snapshot.git_repositories,
|
&new_snapshot.git_repositories,
|
||||||
|
@ -573,7 +581,7 @@ impl LocalWorktree {
|
||||||
*share.snapshots_tx.borrow_mut() = self.snapshot.clone();
|
*share.snapshots_tx.borrow_mut() = self.snapshot.clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
cx.emit(Event::UpdatedEntries);
|
cx.emit(Event::UpdatedEntries(changes));
|
||||||
|
|
||||||
if !updated_repos.is_empty() {
|
if !updated_repos.is_empty() {
|
||||||
cx.emit(Event::UpdatedGitRepositories(updated_repos));
|
cx.emit(Event::UpdatedGitRepositories(updated_repos));
|
||||||
|
@ -602,7 +610,7 @@ impl LocalWorktree {
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
cx.emit(Event::UpdatedEntries);
|
cx.emit(Event::UpdatedEntries(Default::default()));
|
||||||
|
|
||||||
if !updated_repos.is_empty() {
|
if !updated_repos.is_empty() {
|
||||||
cx.emit(Event::UpdatedGitRepositories(updated_repos));
|
cx.emit(Event::UpdatedGitRepositories(updated_repos));
|
||||||
|
@ -994,15 +1002,26 @@ impl LocalWorktree {
|
||||||
let inserted_entry;
|
let inserted_entry;
|
||||||
{
|
{
|
||||||
let mut snapshot = this.background_snapshot.lock();
|
let mut snapshot = this.background_snapshot.lock();
|
||||||
|
let mut changes = this.background_changes.lock();
|
||||||
let mut entry = Entry::new(path, &metadata, &next_entry_id, root_char_bag);
|
let mut entry = Entry::new(path, &metadata, &next_entry_id, root_char_bag);
|
||||||
entry.is_ignored = snapshot
|
entry.is_ignored = snapshot
|
||||||
.ignore_stack_for_abs_path(&abs_path, entry.is_dir())
|
.ignore_stack_for_abs_path(&abs_path, entry.is_dir())
|
||||||
.is_abs_path_ignored(&abs_path, entry.is_dir());
|
.is_abs_path_ignored(&abs_path, entry.is_dir());
|
||||||
if let Some(old_path) = old_path {
|
if let Some(old_path) = old_path {
|
||||||
snapshot.remove_path(&old_path);
|
snapshot.remove_path(&old_path);
|
||||||
|
changes.insert(old_path.clone(), PathChange::Removed);
|
||||||
}
|
}
|
||||||
snapshot.scan_started();
|
snapshot.scan_started();
|
||||||
|
let exists = snapshot.entry_for_path(&entry.path).is_some();
|
||||||
inserted_entry = snapshot.insert_entry(entry, fs.as_ref());
|
inserted_entry = snapshot.insert_entry(entry, fs.as_ref());
|
||||||
|
changes.insert(
|
||||||
|
inserted_entry.path.clone(),
|
||||||
|
if exists {
|
||||||
|
PathChange::Updated
|
||||||
|
} else {
|
||||||
|
PathChange::Added
|
||||||
|
},
|
||||||
|
);
|
||||||
snapshot.scan_completed();
|
snapshot.scan_completed();
|
||||||
}
|
}
|
||||||
this.poll_snapshot(true, cx);
|
this.poll_snapshot(true, cx);
|
||||||
|
@ -1111,7 +1130,7 @@ impl RemoteWorktree {
|
||||||
|
|
||||||
fn poll_snapshot(&mut self, cx: &mut ModelContext<Worktree>) {
|
fn poll_snapshot(&mut self, cx: &mut ModelContext<Worktree>) {
|
||||||
self.snapshot = self.background_snapshot.lock().clone();
|
self.snapshot = self.background_snapshot.lock().clone();
|
||||||
cx.emit(Event::UpdatedEntries);
|
cx.emit(Event::UpdatedEntries(Default::default()));
|
||||||
cx.notify();
|
cx.notify();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2048,6 +2067,13 @@ pub enum EntryKind {
|
||||||
File(CharBag),
|
File(CharBag),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub enum PathChange {
|
||||||
|
Added,
|
||||||
|
Removed,
|
||||||
|
Updated,
|
||||||
|
}
|
||||||
|
|
||||||
impl Entry {
|
impl Entry {
|
||||||
fn new(
|
fn new(
|
||||||
path: Arc<Path>,
|
path: Arc<Path>,
|
||||||
|
@ -2206,6 +2232,7 @@ impl<'a> sum_tree::Dimension<'a, EntrySummary> for PathKey {
|
||||||
struct BackgroundScanner {
|
struct BackgroundScanner {
|
||||||
fs: Arc<dyn Fs>,
|
fs: Arc<dyn Fs>,
|
||||||
snapshot: Arc<Mutex<LocalSnapshot>>,
|
snapshot: Arc<Mutex<LocalSnapshot>>,
|
||||||
|
changes: Arc<Mutex<HashMap<Arc<Path>, PathChange>>>,
|
||||||
notify: UnboundedSender<ScanState>,
|
notify: UnboundedSender<ScanState>,
|
||||||
executor: Arc<executor::Background>,
|
executor: Arc<executor::Background>,
|
||||||
}
|
}
|
||||||
|
@ -2213,6 +2240,7 @@ struct BackgroundScanner {
|
||||||
impl BackgroundScanner {
|
impl BackgroundScanner {
|
||||||
fn new(
|
fn new(
|
||||||
snapshot: Arc<Mutex<LocalSnapshot>>,
|
snapshot: Arc<Mutex<LocalSnapshot>>,
|
||||||
|
changes: Arc<Mutex<HashMap<Arc<Path>, PathChange>>>,
|
||||||
notify: UnboundedSender<ScanState>,
|
notify: UnboundedSender<ScanState>,
|
||||||
fs: Arc<dyn Fs>,
|
fs: Arc<dyn Fs>,
|
||||||
executor: Arc<executor::Background>,
|
executor: Arc<executor::Background>,
|
||||||
|
@ -2220,6 +2248,7 @@ impl BackgroundScanner {
|
||||||
Self {
|
Self {
|
||||||
fs,
|
fs,
|
||||||
snapshot,
|
snapshot,
|
||||||
|
changes,
|
||||||
notify,
|
notify,
|
||||||
executor,
|
executor,
|
||||||
}
|
}
|
||||||
|
@ -2486,12 +2515,14 @@ impl BackgroundScanner {
|
||||||
let root_char_bag;
|
let root_char_bag;
|
||||||
let root_abs_path;
|
let root_abs_path;
|
||||||
let next_entry_id;
|
let next_entry_id;
|
||||||
|
let prev_snapshot;
|
||||||
{
|
{
|
||||||
let mut snapshot = self.snapshot.lock();
|
let mut snapshot = self.snapshot.lock();
|
||||||
snapshot.scan_started();
|
prev_snapshot = snapshot.snapshot.clone();
|
||||||
root_char_bag = snapshot.root_char_bag;
|
root_char_bag = snapshot.root_char_bag;
|
||||||
root_abs_path = snapshot.abs_path.clone();
|
root_abs_path = snapshot.abs_path.clone();
|
||||||
next_entry_id = snapshot.next_entry_id.clone();
|
next_entry_id = snapshot.next_entry_id.clone();
|
||||||
|
snapshot.scan_started();
|
||||||
}
|
}
|
||||||
|
|
||||||
let root_canonical_path = if let Ok(path) = self.fs.canonicalize(&root_abs_path).await {
|
let root_canonical_path = if let Ok(path) = self.fs.canonicalize(&root_abs_path).await {
|
||||||
|
@ -2510,6 +2541,7 @@ impl BackgroundScanner {
|
||||||
// Hold the snapshot lock while clearing and re-inserting the root entries
|
// Hold the snapshot lock while clearing and re-inserting the root entries
|
||||||
// for each event. This way, the snapshot is not observable to the foreground
|
// for each event. This way, the snapshot is not observable to the foreground
|
||||||
// thread while this operation is in-progress.
|
// thread while this operation is in-progress.
|
||||||
|
let mut event_paths = Vec::with_capacity(events.len());
|
||||||
let (scan_queue_tx, scan_queue_rx) = channel::unbounded();
|
let (scan_queue_tx, scan_queue_rx) = channel::unbounded();
|
||||||
{
|
{
|
||||||
let mut snapshot = self.snapshot.lock();
|
let mut snapshot = self.snapshot.lock();
|
||||||
|
@ -2531,6 +2563,7 @@ impl BackgroundScanner {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
event_paths.push(path.clone());
|
||||||
let abs_path = root_abs_path.join(&path);
|
let abs_path = root_abs_path.join(&path);
|
||||||
|
|
||||||
match metadata {
|
match metadata {
|
||||||
|
@ -2599,6 +2632,7 @@ impl BackgroundScanner {
|
||||||
|
|
||||||
self.update_ignore_statuses().await;
|
self.update_ignore_statuses().await;
|
||||||
self.update_git_repositories();
|
self.update_git_repositories();
|
||||||
|
self.build_change_set(prev_snapshot, event_paths);
|
||||||
self.snapshot.lock().scan_completed();
|
self.snapshot.lock().scan_completed();
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
@ -2714,6 +2748,60 @@ impl BackgroundScanner {
|
||||||
snapshot.entries_by_path.edit(entries_by_path_edits, &());
|
snapshot.entries_by_path.edit(entries_by_path_edits, &());
|
||||||
snapshot.entries_by_id.edit(entries_by_id_edits, &());
|
snapshot.entries_by_id.edit(entries_by_id_edits, &());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn build_change_set(&self, old_snapshot: Snapshot, event_paths: Vec<Arc<Path>>) {
|
||||||
|
let new_snapshot = self.snapshot.lock();
|
||||||
|
let mut old_paths = old_snapshot.entries_by_path.cursor::<PathKey>();
|
||||||
|
let mut new_paths = new_snapshot.entries_by_path.cursor::<PathKey>();
|
||||||
|
|
||||||
|
let mut change_set = self.changes.lock();
|
||||||
|
for path in event_paths {
|
||||||
|
let path = PathKey(path);
|
||||||
|
old_paths.seek(&path, Bias::Left, &());
|
||||||
|
new_paths.seek(&path, Bias::Left, &());
|
||||||
|
|
||||||
|
loop {
|
||||||
|
match (old_paths.item(), new_paths.item()) {
|
||||||
|
(Some(old_entry), Some(new_entry)) => {
|
||||||
|
if old_entry.path > path.0
|
||||||
|
&& new_entry.path > path.0
|
||||||
|
&& !old_entry.path.starts_with(&path.0)
|
||||||
|
&& !new_entry.path.starts_with(&path.0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
match Ord::cmp(&old_entry.path, &new_entry.path) {
|
||||||
|
Ordering::Less => {
|
||||||
|
change_set.insert(old_entry.path.clone(), PathChange::Removed);
|
||||||
|
old_paths.next(&());
|
||||||
|
}
|
||||||
|
Ordering::Equal => {
|
||||||
|
if old_entry.mtime != new_entry.mtime {
|
||||||
|
change_set.insert(old_entry.path.clone(), PathChange::Updated);
|
||||||
|
}
|
||||||
|
old_paths.next(&());
|
||||||
|
new_paths.next(&());
|
||||||
|
}
|
||||||
|
Ordering::Greater => {
|
||||||
|
change_set.insert(new_entry.path.clone(), PathChange::Added);
|
||||||
|
new_paths.next(&());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(Some(old_entry), None) => {
|
||||||
|
change_set.insert(old_entry.path.clone(), PathChange::Removed);
|
||||||
|
old_paths.next(&());
|
||||||
|
}
|
||||||
|
(None, Some(new_entry)) => {
|
||||||
|
change_set.insert(new_entry.path.clone(), PathChange::Added);
|
||||||
|
new_paths.next(&());
|
||||||
|
}
|
||||||
|
(None, None) => break,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn char_bag_for_path(root_char_bag: CharBag, path: &Path) -> CharBag {
|
fn char_bag_for_path(root_char_bag: CharBag, path: &Path) -> CharBag {
|
||||||
|
@ -3500,6 +3588,7 @@ mod tests {
|
||||||
);
|
);
|
||||||
let mut scanner = BackgroundScanner::new(
|
let mut scanner = BackgroundScanner::new(
|
||||||
Arc::new(Mutex::new(initial_snapshot.clone())),
|
Arc::new(Mutex::new(initial_snapshot.clone())),
|
||||||
|
Arc::new(Mutex::new(HashMap::default())),
|
||||||
notify_tx,
|
notify_tx,
|
||||||
fs.clone(),
|
fs.clone(),
|
||||||
Arc::new(gpui::executor::Background::new()),
|
Arc::new(gpui::executor::Background::new()),
|
||||||
|
@ -3533,6 +3622,7 @@ mod tests {
|
||||||
let (notify_tx, _notify_rx) = mpsc::unbounded();
|
let (notify_tx, _notify_rx) = mpsc::unbounded();
|
||||||
let mut new_scanner = BackgroundScanner::new(
|
let mut new_scanner = BackgroundScanner::new(
|
||||||
Arc::new(Mutex::new(initial_snapshot)),
|
Arc::new(Mutex::new(initial_snapshot)),
|
||||||
|
Arc::new(Mutex::new(HashMap::default())),
|
||||||
notify_tx,
|
notify_tx,
|
||||||
scanner.fs.clone(),
|
scanner.fs.clone(),
|
||||||
scanner.executor.clone(),
|
scanner.executor.clone(),
|
||||||
|
|
Loading…
Reference in a new issue