mirror of
https://github.com/zed-industries/zed.git
synced 2024-12-28 20:25:44 +03:00
WIP
This commit is contained in:
parent
f836a25500
commit
2ecdc65f38
@ -39,8 +39,14 @@ async fn test_share_worktree(mut cx_a: TestAppContext, mut cx_b: TestAppContext)
|
||||
"a.txt": "a-contents",
|
||||
"b.txt": "b-contents",
|
||||
}));
|
||||
let worktree_a = cx_a
|
||||
.add_model(|cx| Worktree::local(dir.path(), lang_registry.clone(), Arc::new(RealFs), cx));
|
||||
let worktree_a = Worktree::open_local(
|
||||
dir.path(),
|
||||
lang_registry.clone(),
|
||||
Arc::new(RealFs),
|
||||
&mut cx_a.to_async(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
worktree_a
|
||||
.read_with(&cx_a, |tree, _| tree.as_local().unwrap().scan_complete())
|
||||
.await;
|
||||
@ -134,8 +140,14 @@ async fn test_propagate_saves_and_fs_changes_in_shared_worktree(
|
||||
"file1": "",
|
||||
"file2": ""
|
||||
}));
|
||||
let worktree_a = cx_a
|
||||
.add_model(|cx| Worktree::local(dir.path(), lang_registry.clone(), Arc::new(RealFs), cx));
|
||||
let worktree_a = Worktree::open_local(
|
||||
dir.path(),
|
||||
lang_registry.clone(),
|
||||
Arc::new(RealFs),
|
||||
&mut cx_a.to_async(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
worktree_a
|
||||
.read_with(&cx_a, |tree, _| tree.as_local().unwrap().scan_complete())
|
||||
.await;
|
||||
@ -249,8 +261,14 @@ async fn test_buffer_conflict_after_save(mut cx_a: TestAppContext, mut cx_b: Tes
|
||||
fs.save(Path::new("/a.txt"), &"a-contents".into())
|
||||
.await
|
||||
.unwrap();
|
||||
let worktree_a =
|
||||
cx_a.add_model(|cx| Worktree::local(Path::new("/"), lang_registry.clone(), fs.clone(), cx));
|
||||
let worktree_a = Worktree::open_local(
|
||||
"/".as_ref(),
|
||||
lang_registry.clone(),
|
||||
Arc::new(RealFs),
|
||||
&mut cx_a.to_async(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
worktree_a
|
||||
.read_with(&cx_a, |tree, _| tree.as_local().unwrap().scan_complete())
|
||||
.await;
|
||||
@ -320,8 +338,14 @@ async fn test_editing_while_guest_opens_buffer(mut cx_a: TestAppContext, mut cx_
|
||||
fs.save(Path::new("/a.txt"), &"a-contents".into())
|
||||
.await
|
||||
.unwrap();
|
||||
let worktree_a =
|
||||
cx_a.add_model(|cx| Worktree::local(Path::new("/"), lang_registry.clone(), fs.clone(), cx));
|
||||
let worktree_a = Worktree::open_local(
|
||||
"/".as_ref(),
|
||||
lang_registry.clone(),
|
||||
Arc::new(RealFs),
|
||||
&mut cx_a.to_async(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
worktree_a
|
||||
.read_with(&cx_a, |tree, _| tree.as_local().unwrap().scan_complete())
|
||||
.await;
|
||||
@ -373,8 +397,14 @@ async fn test_peer_disconnection(mut cx_a: TestAppContext, cx_b: TestAppContext)
|
||||
"a.txt": "a-contents",
|
||||
"b.txt": "b-contents",
|
||||
}));
|
||||
let worktree_a = cx_a
|
||||
.add_model(|cx| Worktree::local(dir.path(), lang_registry.clone(), Arc::new(RealFs), cx));
|
||||
let worktree_a = Worktree::open_local(
|
||||
dir.path(),
|
||||
lang_registry.clone(),
|
||||
Arc::new(RealFs),
|
||||
&mut cx_a.to_async(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
worktree_a
|
||||
.read_with(&cx_a, |tree, _| tree.as_local().unwrap().scan_complete())
|
||||
.await;
|
||||
|
@ -3209,8 +3209,14 @@ mod tests {
|
||||
"file2": "def",
|
||||
"file3": "ghi",
|
||||
}));
|
||||
let tree = cx
|
||||
.add_model(|cx| Worktree::local(dir.path(), Default::default(), Arc::new(RealFs), cx));
|
||||
let tree = Worktree::open_local(
|
||||
dir.path(),
|
||||
Default::default(),
|
||||
Arc::new(RealFs),
|
||||
&mut cx.to_async(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
tree.flush_fs_events(&cx).await;
|
||||
cx.read(|cx| tree.read(cx).as_local().unwrap().scan_complete())
|
||||
.await;
|
||||
@ -3322,8 +3328,14 @@ mod tests {
|
||||
async fn test_file_changes_on_disk(mut cx: gpui::TestAppContext) {
|
||||
let initial_contents = "aaa\nbbbbb\nc\n";
|
||||
let dir = temp_tree(json!({ "the-file": initial_contents }));
|
||||
let tree = cx
|
||||
.add_model(|cx| Worktree::local(dir.path(), Default::default(), Arc::new(RealFs), cx));
|
||||
let tree = Worktree::open_local(
|
||||
dir.path(),
|
||||
Default::default(),
|
||||
Arc::new(RealFs),
|
||||
&mut cx.to_async(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
cx.read(|cx| tree.read(cx).as_local().unwrap().scan_complete())
|
||||
.await;
|
||||
|
||||
|
@ -476,11 +476,13 @@ mod tests {
|
||||
});
|
||||
|
||||
let app_state = cx.read(build_app_state);
|
||||
let (window_id, workspace) = cx.add_window(|cx| {
|
||||
let mut workspace = Workspace::new(&app_state, cx);
|
||||
workspace.add_worktree(tmp_dir.path(), cx);
|
||||
workspace
|
||||
});
|
||||
let (window_id, workspace) = cx.add_window(|cx| Workspace::new(&app_state, cx));
|
||||
workspace
|
||||
.update(&mut cx, |workspace, cx| {
|
||||
workspace.add_worktree(tmp_dir.path(), cx)
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
cx.read(|cx| workspace.read(cx).worktree_scans_complete(cx))
|
||||
.await;
|
||||
cx.dispatch_action(
|
||||
@ -543,11 +545,13 @@ mod tests {
|
||||
"hiccup": "",
|
||||
}));
|
||||
let app_state = cx.read(build_app_state);
|
||||
let (_, workspace) = cx.add_window(|cx| {
|
||||
let mut workspace = Workspace::new(&app_state, cx);
|
||||
workspace.add_worktree(tmp_dir.path(), cx);
|
||||
workspace
|
||||
});
|
||||
let (_, workspace) = cx.add_window(|cx| Workspace::new(&app_state, cx));
|
||||
workspace
|
||||
.update(&mut cx, |workspace, cx| {
|
||||
workspace.add_worktree(tmp_dir.path(), cx)
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
cx.read(|cx| workspace.read(cx).worktree_scans_complete(cx))
|
||||
.await;
|
||||
let (_, finder) =
|
||||
@ -601,11 +605,13 @@ mod tests {
|
||||
fs::write(&file_path, "").unwrap();
|
||||
|
||||
let app_state = cx.read(build_app_state);
|
||||
let (_, workspace) = cx.add_window(|cx| {
|
||||
let mut workspace = Workspace::new(&app_state, cx);
|
||||
workspace.add_worktree(&file_path, cx);
|
||||
workspace
|
||||
});
|
||||
let (_, workspace) = cx.add_window(|cx| Workspace::new(&app_state, cx));
|
||||
workspace
|
||||
.update(&mut cx, |workspace, cx| {
|
||||
workspace.add_worktree(&file_path, cx)
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
cx.read(|cx| workspace.read(cx).worktree_scans_complete(cx))
|
||||
.await;
|
||||
let (_, finder) =
|
||||
|
@ -402,70 +402,89 @@ impl Workspace {
|
||||
cx.spawn(|this, mut cx| {
|
||||
let fs = fs.clone();
|
||||
async move {
|
||||
let entry_id = entry_id.await?;
|
||||
if fs.is_file(&abs_path).await {
|
||||
return this.update(&mut cx, |this, cx| this.open_entry(entry_id, cx));
|
||||
} else {
|
||||
None
|
||||
if let Some(entry) =
|
||||
this.update(&mut cx, |this, cx| this.open_entry(entry_id, cx))
|
||||
{
|
||||
entry.await;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
})
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
.collect::<Vec<Task<Result<()>>>>();
|
||||
async move {
|
||||
for task in tasks {
|
||||
if let Some(task) = task.await {
|
||||
task.await;
|
||||
if let Err(error) = task.await {
|
||||
log::error!("error opening paths {}", error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn worktree_for_abs_path(
|
||||
&mut self,
|
||||
&self,
|
||||
abs_path: &Path,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) -> (ModelHandle<Worktree>, PathBuf) {
|
||||
for tree in self.worktrees.iter() {
|
||||
if let Some(path) = tree
|
||||
.read(cx)
|
||||
.as_local()
|
||||
.and_then(|tree| abs_path.strip_prefix(&tree.abs_path()).ok())
|
||||
{
|
||||
return (tree.clone(), path.to_path_buf());
|
||||
) -> Task<Result<(ModelHandle<Worktree>, PathBuf)>> {
|
||||
let abs_path: Arc<Path> = Arc::from(abs_path);
|
||||
cx.spawn(|this, mut cx| async move {
|
||||
let mut entry_id = None;
|
||||
this.read_with(&cx, |this, cx| {
|
||||
for tree in this.worktrees.iter() {
|
||||
if let Some(relative_path) = tree
|
||||
.read(cx)
|
||||
.as_local()
|
||||
.and_then(|t| abs_path.strip_prefix(t.abs_path()).ok())
|
||||
{
|
||||
entry_id = Some((tree.clone(), relative_path.into()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if let Some(entry_id) = entry_id {
|
||||
Ok(entry_id)
|
||||
} else {
|
||||
let worktree = this
|
||||
.update(&mut cx, |this, cx| this.add_worktree(&abs_path, cx))
|
||||
.await?;
|
||||
Ok((worktree, PathBuf::new()))
|
||||
}
|
||||
}
|
||||
(self.add_worktree(abs_path, cx), PathBuf::new())
|
||||
})
|
||||
}
|
||||
|
||||
fn entry_id_for_path(
|
||||
&mut self,
|
||||
&self,
|
||||
abs_path: &Path,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) -> (usize, Arc<Path>) {
|
||||
for tree in self.worktrees.iter() {
|
||||
if let Some(relative_path) = tree
|
||||
.read(cx)
|
||||
.as_local()
|
||||
.and_then(|t| abs_path.strip_prefix(t.abs_path()).ok())
|
||||
{
|
||||
return (tree.id(), relative_path.into());
|
||||
}
|
||||
}
|
||||
let worktree = self.add_worktree(&abs_path, cx);
|
||||
(worktree.id(), Path::new("").into())
|
||||
) -> Task<Result<(usize, Arc<Path>)>> {
|
||||
let entry = self.worktree_for_abs_path(abs_path, cx);
|
||||
cx.spawn(|_, _| async move {
|
||||
let (worktree, path) = entry.await?;
|
||||
Ok((worktree.id(), path.into()))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn add_worktree(
|
||||
&mut self,
|
||||
&self,
|
||||
path: &Path,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) -> ModelHandle<Worktree> {
|
||||
let worktree =
|
||||
cx.add_model(|cx| Worktree::local(path, self.languages.clone(), self.fs.clone(), cx));
|
||||
cx.observe_model(&worktree, |_, _, cx| cx.notify());
|
||||
self.worktrees.insert(worktree.clone());
|
||||
cx.notify();
|
||||
worktree
|
||||
) -> Task<Result<ModelHandle<Worktree>>> {
|
||||
let languages = self.languages.clone();
|
||||
let fs = self.fs.clone();
|
||||
let path = Arc::from(path);
|
||||
cx.spawn(|this, mut cx| async move {
|
||||
let worktree = Worktree::open_local(path, languages, fs, &mut cx).await?;
|
||||
this.update(&mut cx, |this, cx| {
|
||||
cx.observe_model(&worktree, |_, _, cx| cx.notify());
|
||||
this.worktrees.insert(worktree.clone());
|
||||
cx.notify();
|
||||
});
|
||||
Ok(worktree)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn toggle_modal<V, F>(&mut self, cx: &mut ViewContext<Self>, add_view: F)
|
||||
@ -640,12 +659,22 @@ impl Workspace {
|
||||
cx.prompt_for_new_path(&start_abs_path, move |abs_path, cx| {
|
||||
if let Some(abs_path) = abs_path {
|
||||
cx.spawn(|mut cx| async move {
|
||||
let result = handle
|
||||
.update(&mut cx, |me, cx| {
|
||||
let (worktree, path) = me.worktree_for_abs_path(&abs_path, cx);
|
||||
item.save_as(&worktree, &path, cx.as_mut())
|
||||
let result = match handle
|
||||
.update(&mut cx, |this, cx| {
|
||||
this.worktree_for_abs_path(&abs_path, cx)
|
||||
})
|
||||
.await;
|
||||
.await
|
||||
{
|
||||
Ok((worktree, path)) => {
|
||||
handle
|
||||
.update(&mut cx, |_, cx| {
|
||||
item.save_as(&worktree, &path, cx.as_mut())
|
||||
})
|
||||
.await
|
||||
}
|
||||
Err(error) => Err(error),
|
||||
};
|
||||
|
||||
if let Err(error) = result {
|
||||
error!("failed to save item: {:?}, ", error);
|
||||
}
|
||||
@ -974,11 +1003,13 @@ mod tests {
|
||||
|
||||
let app_state = cx.read(build_app_state);
|
||||
|
||||
let (_, workspace) = cx.add_window(|cx| {
|
||||
let mut workspace = Workspace::new(&app_state, cx);
|
||||
workspace.add_worktree(dir.path(), cx);
|
||||
workspace
|
||||
});
|
||||
let (_, workspace) = cx.add_window(|cx| Workspace::new(&app_state, cx));
|
||||
workspace
|
||||
.update(&mut cx, |workspace, cx| {
|
||||
workspace.add_worktree(dir.path(), cx)
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
cx.read(|cx| workspace.read(cx).worktree_scans_complete(cx))
|
||||
.await;
|
||||
@ -1077,11 +1108,13 @@ mod tests {
|
||||
let mut app_state = cx.read(build_app_state);
|
||||
Arc::get_mut(&mut app_state).unwrap().fs = Arc::new(fs);
|
||||
|
||||
let (_, workspace) = cx.add_window(|cx| {
|
||||
let mut workspace = Workspace::new(&app_state, cx);
|
||||
workspace.add_worktree("/dir1".as_ref(), cx);
|
||||
workspace
|
||||
});
|
||||
let (_, workspace) = cx.add_window(|cx| Workspace::new(&app_state, cx));
|
||||
workspace
|
||||
.update(&mut cx, |workspace, cx| {
|
||||
workspace.add_worktree("/dir1".as_ref(), cx)
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
cx.read(|cx| workspace.read(cx).worktree_scans_complete(cx))
|
||||
.await;
|
||||
|
||||
@ -1142,11 +1175,13 @@ mod tests {
|
||||
}));
|
||||
|
||||
let app_state = cx.read(build_app_state);
|
||||
let (window_id, workspace) = cx.add_window(|cx| {
|
||||
let mut workspace = Workspace::new(&app_state, cx);
|
||||
workspace.add_worktree(dir.path(), cx);
|
||||
workspace
|
||||
});
|
||||
let (window_id, workspace) = cx.add_window(|cx| Workspace::new(&app_state, cx));
|
||||
workspace
|
||||
.update(&mut cx, |workspace, cx| {
|
||||
workspace.add_worktree(dir.path(), cx)
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
let tree = cx.read(|cx| {
|
||||
let mut trees = workspace.read(cx).worktrees().iter();
|
||||
trees.next().unwrap().clone()
|
||||
@ -1185,11 +1220,13 @@ mod tests {
|
||||
async fn test_open_and_save_new_file(mut cx: gpui::TestAppContext) {
|
||||
let dir = TempDir::new("test-new-file").unwrap();
|
||||
let app_state = cx.read(build_app_state);
|
||||
let (_, workspace) = cx.add_window(|cx| {
|
||||
let mut workspace = Workspace::new(&app_state, cx);
|
||||
workspace.add_worktree(dir.path(), cx);
|
||||
workspace
|
||||
});
|
||||
let (_, workspace) = cx.add_window(|cx| Workspace::new(&app_state, cx));
|
||||
workspace
|
||||
.update(&mut cx, |workspace, cx| {
|
||||
workspace.add_worktree(dir.path(), cx)
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
let tree = cx.read(|cx| {
|
||||
workspace
|
||||
.read(cx)
|
||||
@ -1305,11 +1342,13 @@ mod tests {
|
||||
}));
|
||||
|
||||
let app_state = cx.read(build_app_state);
|
||||
let (window_id, workspace) = cx.add_window(|cx| {
|
||||
let mut workspace = Workspace::new(&app_state, cx);
|
||||
workspace.add_worktree(dir.path(), cx);
|
||||
workspace
|
||||
});
|
||||
let (window_id, workspace) = cx.add_window(|cx| Workspace::new(&app_state, cx));
|
||||
workspace
|
||||
.update(&mut cx, |workspace, cx| {
|
||||
workspace.add_worktree(dir.path(), cx)
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
cx.read(|cx| workspace.read(cx).worktree_scans_complete(cx))
|
||||
.await;
|
||||
let entries = cx.read(|cx| workspace.file_entries(cx));
|
||||
|
@ -541,23 +541,26 @@ impl Entity for Worktree {
|
||||
}
|
||||
|
||||
impl Worktree {
|
||||
pub fn local(
|
||||
pub async fn open_local(
|
||||
path: impl Into<Arc<Path>>,
|
||||
languages: Arc<LanguageRegistry>,
|
||||
fs: Arc<dyn Fs>,
|
||||
cx: &mut ModelContext<Worktree>,
|
||||
) -> Self {
|
||||
let (mut tree, scan_states_tx) = LocalWorktree::new(path, languages, fs.clone(), cx);
|
||||
let abs_path = tree.snapshot.abs_path.clone();
|
||||
let background_snapshot = tree.background_snapshot.clone();
|
||||
let thread_pool = cx.thread_pool().clone();
|
||||
tree._background_scanner_task = Some(cx.background().spawn(async move {
|
||||
let events = fs.watch(&abs_path, Duration::from_millis(100)).await;
|
||||
let scanner =
|
||||
BackgroundScanner::new(background_snapshot, scan_states_tx, fs, thread_pool);
|
||||
scanner.run(events).await;
|
||||
}));
|
||||
Worktree::Local(tree)
|
||||
cx: &mut AsyncAppContext,
|
||||
) -> Result<ModelHandle<Self>> {
|
||||
let (tree, scan_states_tx) = LocalWorktree::new(path, languages, fs.clone(), cx).await?;
|
||||
tree.update(cx, |tree, cx| {
|
||||
let tree = tree.as_local_mut().unwrap();
|
||||
let abs_path = tree.snapshot.abs_path.clone();
|
||||
let background_snapshot = tree.background_snapshot.clone();
|
||||
let thread_pool = cx.thread_pool().clone();
|
||||
tree._background_scanner_task = Some(cx.background().spawn(async move {
|
||||
let events = fs.watch(&abs_path, Duration::from_millis(100)).await;
|
||||
let scanner =
|
||||
BackgroundScanner::new(background_snapshot, scan_states_tx, fs, thread_pool);
|
||||
scanner.run(events).await;
|
||||
}));
|
||||
});
|
||||
Ok(tree)
|
||||
}
|
||||
|
||||
pub async fn open_remote(
|
||||
@ -1016,75 +1019,99 @@ pub struct LocalWorktree {
|
||||
}
|
||||
|
||||
impl LocalWorktree {
|
||||
fn new(
|
||||
async fn new(
|
||||
path: impl Into<Arc<Path>>,
|
||||
languages: Arc<LanguageRegistry>,
|
||||
fs: Arc<dyn Fs>,
|
||||
cx: &mut ModelContext<Worktree>,
|
||||
) -> (Self, Sender<ScanState>) {
|
||||
cx: &mut AsyncAppContext,
|
||||
) -> Result<(ModelHandle<Worktree>, Sender<ScanState>)> {
|
||||
let abs_path = path.into();
|
||||
let path: Arc<Path> = Arc::from(Path::new(""));
|
||||
let next_entry_id = AtomicUsize::new(0);
|
||||
|
||||
// After determining whether the root entry is a file or a directory, populate the
|
||||
// snapshot's "root name", which will be used for the purpose of fuzzy matching.
|
||||
let mut root_name = abs_path
|
||||
.file_name()
|
||||
.map_or(String::new(), |f| f.to_string_lossy().to_string());
|
||||
let root_char_bag = root_name.chars().map(|c| c.to_ascii_lowercase()).collect();
|
||||
let entry = fs
|
||||
.entry(root_char_bag, &next_entry_id, path.clone(), &abs_path)
|
||||
.await?
|
||||
.ok_or_else(|| anyhow!("root entry does not exist"))?;
|
||||
let is_dir = entry.is_dir();
|
||||
if is_dir {
|
||||
root_name.push('/');
|
||||
}
|
||||
|
||||
let (scan_states_tx, scan_states_rx) = smol::channel::unbounded();
|
||||
let (mut last_scan_state_tx, last_scan_state_rx) = watch::channel_with(ScanState::Scanning);
|
||||
let id = cx.model_id();
|
||||
let snapshot = Snapshot {
|
||||
id,
|
||||
scan_id: 0,
|
||||
abs_path,
|
||||
root_name: Default::default(),
|
||||
root_char_bag: Default::default(),
|
||||
ignores: Default::default(),
|
||||
entries_by_path: Default::default(),
|
||||
entries_by_id: Default::default(),
|
||||
removed_entry_ids: Default::default(),
|
||||
next_entry_id: Default::default(),
|
||||
};
|
||||
let tree = cx.add_model(move |cx: &mut ModelContext<Worktree>| {
|
||||
let mut snapshot = Snapshot {
|
||||
id: cx.model_id(),
|
||||
scan_id: 0,
|
||||
abs_path,
|
||||
root_name,
|
||||
root_char_bag,
|
||||
ignores: Default::default(),
|
||||
entries_by_path: Default::default(),
|
||||
entries_by_id: Default::default(),
|
||||
removed_entry_ids: Default::default(),
|
||||
next_entry_id: Arc::new(next_entry_id),
|
||||
};
|
||||
snapshot.insert_entry(entry);
|
||||
|
||||
let tree = Self {
|
||||
snapshot: snapshot.clone(),
|
||||
background_snapshot: Arc::new(Mutex::new(snapshot)),
|
||||
snapshots_to_send_tx: None,
|
||||
last_scan_state_rx,
|
||||
_background_scanner_task: None,
|
||||
poll_scheduled: false,
|
||||
open_buffers: Default::default(),
|
||||
shared_buffers: Default::default(),
|
||||
peers: Default::default(),
|
||||
rpc: None,
|
||||
languages,
|
||||
fs,
|
||||
};
|
||||
let tree = Self {
|
||||
snapshot: snapshot.clone(),
|
||||
background_snapshot: Arc::new(Mutex::new(snapshot)),
|
||||
snapshots_to_send_tx: None,
|
||||
last_scan_state_rx,
|
||||
_background_scanner_task: None,
|
||||
poll_scheduled: false,
|
||||
open_buffers: Default::default(),
|
||||
shared_buffers: Default::default(),
|
||||
peers: Default::default(),
|
||||
rpc: None,
|
||||
languages,
|
||||
fs,
|
||||
};
|
||||
|
||||
cx.spawn_weak(|this, mut cx| async move {
|
||||
while let Ok(scan_state) = scan_states_rx.recv().await {
|
||||
if let Some(handle) = cx.read(|cx| this.upgrade(&cx)) {
|
||||
let to_send = handle.update(&mut cx, |this, cx| {
|
||||
last_scan_state_tx.blocking_send(scan_state).ok();
|
||||
this.poll_snapshot(cx);
|
||||
let tree = this.as_local_mut().unwrap();
|
||||
if !tree.is_scanning() {
|
||||
if let Some(snapshots_to_send_tx) = tree.snapshots_to_send_tx.clone() {
|
||||
Some((tree.snapshot(), snapshots_to_send_tx))
|
||||
cx.spawn_weak(|this, mut cx| async move {
|
||||
while let Ok(scan_state) = scan_states_rx.recv().await {
|
||||
if let Some(handle) = cx.read(|cx| this.upgrade(&cx)) {
|
||||
let to_send = handle.update(&mut cx, |this, cx| {
|
||||
last_scan_state_tx.blocking_send(scan_state).ok();
|
||||
this.poll_snapshot(cx);
|
||||
let tree = this.as_local_mut().unwrap();
|
||||
if !tree.is_scanning() {
|
||||
if let Some(snapshots_to_send_tx) =
|
||||
tree.snapshots_to_send_tx.clone()
|
||||
{
|
||||
Some((tree.snapshot(), snapshots_to_send_tx))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
if let Some((snapshot, snapshots_to_send_tx)) = to_send {
|
||||
if let Err(err) = snapshots_to_send_tx.send(snapshot).await {
|
||||
log::error!("error submitting snapshot to send {}", err);
|
||||
if let Some((snapshot, snapshots_to_send_tx)) = to_send {
|
||||
if let Err(err) = snapshots_to_send_tx.send(snapshot).await {
|
||||
log::error!("error submitting snapshot to send {}", err);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
})
|
||||
.detach();
|
||||
})
|
||||
.detach();
|
||||
|
||||
(tree, scan_states_tx)
|
||||
Worktree::Local(tree)
|
||||
});
|
||||
|
||||
Ok((tree, scan_states_tx))
|
||||
}
|
||||
|
||||
pub fn open_buffer(
|
||||
@ -1890,9 +1917,8 @@ impl File {
|
||||
/// Returns the last component of this handle's absolute path. If this handle refers to the root
|
||||
/// of its worktree, then this method will return the name of the worktree itself.
|
||||
pub fn file_name<'a>(&'a self, cx: &'a AppContext) -> Option<OsString> {
|
||||
self.path
|
||||
.file_name()
|
||||
.or_else(|| Some(OsStr::new(self.worktree.read(cx).root_name())))
|
||||
dbg!(self.path.file_name())
|
||||
.or_else(|| Some(OsStr::new(dbg!(self.worktree.read(cx).root_name()))))
|
||||
.map(Into::into)
|
||||
}
|
||||
|
||||
@ -2242,40 +2268,19 @@ impl BackgroundScanner {
|
||||
}
|
||||
|
||||
async fn scan_dirs(&mut self) -> Result<()> {
|
||||
let root_char_bag;
|
||||
let next_entry_id;
|
||||
let is_dir;
|
||||
{
|
||||
let mut snapshot = self.snapshot.lock();
|
||||
snapshot.scan_id += 1;
|
||||
let snapshot = self.snapshot.lock();
|
||||
root_char_bag = snapshot.root_char_bag;
|
||||
next_entry_id = snapshot.next_entry_id.clone();
|
||||
is_dir = snapshot.root_entry().is_dir();
|
||||
}
|
||||
|
||||
let path: Arc<Path> = Arc::from(Path::new(""));
|
||||
let abs_path = self.abs_path();
|
||||
|
||||
// After determining whether the root entry is a file or a directory, populate the
|
||||
// snapshot's "root name", which will be used for the purpose of fuzzy matching.
|
||||
let mut root_name = abs_path
|
||||
.file_name()
|
||||
.map_or(String::new(), |f| f.to_string_lossy().to_string());
|
||||
let root_char_bag = root_name.chars().map(|c| c.to_ascii_lowercase()).collect();
|
||||
let entry = self
|
||||
.fs
|
||||
.entry(root_char_bag, &next_entry_id, path.clone(), &abs_path)
|
||||
.await?
|
||||
.ok_or_else(|| anyhow!("root entry does not exist"))?;
|
||||
let is_dir = entry.is_dir();
|
||||
if is_dir {
|
||||
root_name.push('/');
|
||||
}
|
||||
|
||||
{
|
||||
let mut snapshot = self.snapshot.lock();
|
||||
snapshot.root_name = root_name;
|
||||
snapshot.root_char_bag = root_char_bag;
|
||||
}
|
||||
|
||||
self.snapshot.lock().insert_entry(entry);
|
||||
if is_dir {
|
||||
let path: Arc<Path> = Arc::from(Path::new(""));
|
||||
let abs_path = self.abs_path();
|
||||
let (tx, rx) = channel::unbounded();
|
||||
tx.send(ScanJob {
|
||||
abs_path: abs_path.to_path_buf(),
|
||||
@ -2983,7 +2988,7 @@ mod tests {
|
||||
use std::{env, fmt::Write, os::unix, time::SystemTime};
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_populate_and_search(mut cx: gpui::TestAppContext) {
|
||||
async fn test_populate_and_search(cx: gpui::TestAppContext) {
|
||||
let dir = temp_tree(json!({
|
||||
"root": {
|
||||
"apple": "",
|
||||
@ -3007,9 +3012,14 @@ mod tests {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let tree = cx.add_model(|cx| {
|
||||
Worktree::local(root_link_path, Default::default(), Arc::new(RealFs), cx)
|
||||
});
|
||||
let tree = Worktree::open_local(
|
||||
root_link_path,
|
||||
Default::default(),
|
||||
Arc::new(RealFs),
|
||||
&mut cx.to_async(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
cx.read(|cx| tree.read(cx).as_local().unwrap().scan_complete())
|
||||
.await;
|
||||
@ -3055,14 +3065,14 @@ mod tests {
|
||||
let dir = temp_tree(json!({
|
||||
"file1": "the old contents",
|
||||
}));
|
||||
let tree = cx.add_model(|cx| {
|
||||
Worktree::local(
|
||||
dir.path(),
|
||||
app_state.languages.clone(),
|
||||
Arc::new(RealFs),
|
||||
cx,
|
||||
)
|
||||
});
|
||||
let tree = Worktree::open_local(
|
||||
dir.path(),
|
||||
app_state.languages.clone(),
|
||||
Arc::new(RealFs),
|
||||
&mut cx.to_async(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
let buffer = tree
|
||||
.update(&mut cx, |tree, cx| tree.open_buffer("file1", cx))
|
||||
.await
|
||||
@ -3085,14 +3095,14 @@ mod tests {
|
||||
}));
|
||||
let file_path = dir.path().join("file1");
|
||||
|
||||
let tree = cx.add_model(|cx| {
|
||||
Worktree::local(
|
||||
file_path.clone(),
|
||||
app_state.languages.clone(),
|
||||
Arc::new(RealFs),
|
||||
cx,
|
||||
)
|
||||
});
|
||||
let tree = Worktree::open_local(
|
||||
file_path.clone(),
|
||||
app_state.languages.clone(),
|
||||
Arc::new(RealFs),
|
||||
&mut cx.to_async(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
cx.read(|cx| tree.read(cx).as_local().unwrap().scan_complete())
|
||||
.await;
|
||||
cx.read(|cx| assert_eq!(tree.read(cx).file_count(), 1));
|
||||
@ -3127,8 +3137,14 @@ mod tests {
|
||||
}
|
||||
}));
|
||||
|
||||
let tree = cx
|
||||
.add_model(|cx| Worktree::local(dir.path(), Default::default(), Arc::new(RealFs), cx));
|
||||
let tree = Worktree::open_local(
|
||||
dir.path(),
|
||||
Default::default(),
|
||||
Arc::new(RealFs),
|
||||
&mut cx.to_async(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let buffer_for_path = |path: &'static str, cx: &mut gpui::TestAppContext| {
|
||||
let buffer = tree.update(cx, |tree, cx| tree.open_buffer(path, cx));
|
||||
@ -3263,7 +3279,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_rescan_with_gitignore(mut cx: gpui::TestAppContext) {
|
||||
async fn test_rescan_with_gitignore(cx: gpui::TestAppContext) {
|
||||
let dir = temp_tree(json!({
|
||||
".git": {},
|
||||
".gitignore": "ignored-dir\n",
|
||||
@ -3275,8 +3291,14 @@ mod tests {
|
||||
}
|
||||
}));
|
||||
|
||||
let tree = cx
|
||||
.add_model(|cx| Worktree::local(dir.path(), Default::default(), Arc::new(RealFs), cx));
|
||||
let tree = Worktree::open_local(
|
||||
dir.path(),
|
||||
Default::default(),
|
||||
Arc::new(RealFs),
|
||||
&mut cx.to_async(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
cx.read(|cx| tree.read(cx).as_local().unwrap().scan_complete())
|
||||
.await;
|
||||
tree.flush_fs_events(&cx).await;
|
||||
|
Loading…
Reference in New Issue
Block a user