From a2a6d67e1e1b378fddb76eafc94044c04bce51ee Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 18 Jun 2021 13:32:38 -0700 Subject: [PATCH] Start work on implementing ::file on remote WorktreeHandles --- zed/src/editor/buffer.rs | 8 ++-- zed/src/workspace.rs | 56 ++++++++++++++++----------- zed/src/worktree.rs | 80 +++++++++++++++++++-------------------- zed/src/worktree/fuzzy.rs | 2 +- 4 files changed, 76 insertions(+), 70 deletions(-) diff --git a/zed/src/editor/buffer.rs b/zed/src/editor/buffer.rs index 7db4d7a417..1ca98c7298 100644 --- a/zed/src/editor/buffer.rs +++ b/zed/src/editor/buffer.rs @@ -2687,7 +2687,7 @@ mod tests { cx.read(|cx| tree.read(cx).as_local().unwrap().scan_complete()) .await; - let file1 = cx.update(|cx| tree.file("file1", cx)).await; + let file1 = cx.update(|cx| tree.file("file1", cx)).await.unwrap(); let buffer1 = cx.add_model(|cx| { Buffer::from_history(0, History::new("abc".into()), Some(file1), None, cx) }); @@ -2747,7 +2747,7 @@ mod tests { // When a file is deleted, the buffer is considered dirty. let events = Rc::new(RefCell::new(Vec::new())); - let file2 = cx.update(|cx| tree.file("file2", cx)).await; + let file2 = cx.update(|cx| tree.file("file2", cx)).await.unwrap(); let buffer2 = cx.add_model(|cx: &mut ModelContext| { cx.subscribe(&cx.handle(), { let events = events.clone(); @@ -2766,7 +2766,7 @@ mod tests { // When a file is already dirty when deleted, we don't emit a Dirtied event. let events = Rc::new(RefCell::new(Vec::new())); - let file3 = cx.update(|cx| tree.file("file3", cx)).await; + let file3 = cx.update(|cx| tree.file("file3", cx)).await.unwrap(); let buffer3 = cx.add_model(|cx: &mut ModelContext| { cx.subscribe(&cx.handle(), { let events = events.clone(); @@ -2799,7 +2799,7 @@ mod tests { .await; let abs_path = dir.path().join("the-file"); - let file = cx.update(|cx| tree.file("the-file", cx)).await; + let file = cx.update(|cx| tree.file("the-file", cx)).await.unwrap(); let buffer = cx.add_model(|cx| { Buffer::from_history( 0, diff --git a/zed/src/workspace.rs b/zed/src/workspace.rs index bb42aee8c4..e97c4527d8 100644 --- a/zed/src/workspace.rs +++ b/zed/src/workspace.rs @@ -10,7 +10,7 @@ use crate::{ worktree::{FileHandle, Worktree, WorktreeHandle}, AppState, }; -use anyhow::anyhow; +use anyhow::{anyhow, Result}; use gpui::{ color::rgbu, elements::*, json::to_string_pretty, keymap::Binding, AnyViewHandle, AppContext, AsyncAppContext, ClipboardItem, Entity, ModelHandle, MutableAppContext, PathPromptOptions, @@ -23,6 +23,7 @@ use postage::watch; use smol::prelude::*; use std::{ collections::{hash_map::Entry, HashMap, HashSet}, + convert::TryInto, future::Future, path::{Path, PathBuf}, sync::Arc, @@ -404,15 +405,13 @@ impl Workspace { .map(|(abs_path, file)| { let is_file = bg.spawn(async move { abs_path.is_file() }); cx.spawn(|this, mut cx| async move { - let file = file.await; - let is_file = is_file.await; - this.update(&mut cx, |this, cx| { - if is_file { - this.open_entry(file.entry_id(), cx) - } else { - None + if let Ok(file) = file.await { + if is_file.await { + return this + .update(&mut cx, |this, cx| this.open_entry(file.entry_id(), cx)); } - }) + } + None }) }) .collect::>(); @@ -425,7 +424,11 @@ impl Workspace { } } - fn file_for_path(&mut self, abs_path: &Path, cx: &mut ViewContext) -> Task { + fn file_for_path( + &mut self, + abs_path: &Path, + cx: &mut ViewContext, + ) -> Task> { for tree in self.worktrees.iter() { if let Some(relative_path) = tree .read(cx) @@ -546,12 +549,11 @@ impl Workspace { cx.as_mut() .spawn(|mut cx| async move { - let file = file.await; - let history = cx.read(|cx| file.load_history(cx)); - let history = cx.background_executor().spawn(history).await; - - *tx.borrow_mut() = Some(match history { - Ok(history) => Ok(Box::new(cx.add_model(|cx| { + let buffer = async move { + let file = file.await?; + let history = cx.read(|cx| file.load_history(cx)); + let history = cx.background_executor().spawn(history).await?; + let buffer = cx.add_model(|cx| { let language = language_registry.select_language(path); Buffer::from_history( replica_id, @@ -560,9 +562,11 @@ impl Workspace { language.cloned(), cx, ) - }))), - Err(error) => Err(Arc::new(error)), - }) + }); + Ok(Box::new(buffer) as Box) + } + .await; + *tx.borrow_mut() = Some(buffer.map_err(Arc::new)); }) .detach(); } @@ -612,10 +616,14 @@ impl Workspace { cx.prompt_for_new_path(&start_path, move |path, cx| { if let Some(path) = path { cx.spawn(|mut cx| async move { - let file = handle - .update(&mut cx, |me, cx| me.file_for_path(&path, cx)) - .await; - if let Err(error) = cx.update(|cx| item.save(Some(file), cx)).await { + let result = async move { + let file = handle + .update(&mut cx, |me, cx| me.file_for_path(&path, cx)) + .await?; + cx.update(|cx| item.save(Some(file), cx)).await + } + .await; + if let Err(error) = result { error!("failed to save item: {:?}, ", error); } }) @@ -728,6 +736,8 @@ impl Workspace { let worktree = open_worktree_response .worktree .ok_or_else(|| anyhow!("empty worktree"))?; + + let worktree_id = worktree_id.try_into().unwrap(); this.update(&mut cx, |workspace, cx| { let worktree = cx.add_model(|cx| { Worktree::remote(worktree_id, worktree, rpc, connection_id, cx) diff --git a/zed/src/worktree.rs b/zed/src/worktree.rs index 32b39e02ed..e003522cd6 100644 --- a/zed/src/worktree.rs +++ b/zed/src/worktree.rs @@ -30,7 +30,7 @@ use std::{ os::unix::{ffi::OsStrExt, fs::MetadataExt}, path::{Path, PathBuf}, sync::{Arc, Weak}, - time::{Duration, SystemTime, UNIX_EPOCH}, + time::{Duration, SystemTime}, }; use self::{char_bag::CharBag, ignore::IgnoreStack}; @@ -61,7 +61,7 @@ impl Worktree { } pub fn remote( - id: u64, + id: usize, worktree: proto::Worktree, rpc: rpc::Client, connection_id: ConnectionId, @@ -155,7 +155,7 @@ impl LocalWorktree { fn new(path: impl Into>, cx: &mut ModelContext) -> Self { let abs_path = path.into(); let (scan_state_tx, scan_state_rx) = smol::channel::unbounded(); - let id = cx.model_id() as u64; + let id = cx.model_id(); let snapshot = Snapshot { id, scan_id: 0, @@ -374,7 +374,7 @@ impl fmt::Debug for LocalWorktree { } pub struct RemoteWorktree { - id: u64, + id: usize, snapshot: Snapshot, handles: Arc, Weak>>>>, rpc: rpc::Client, @@ -383,7 +383,7 @@ pub struct RemoteWorktree { impl RemoteWorktree { fn new( - id: u64, + id: usize, worktree: proto::Worktree, rpc: rpc::Client, connection_id: ConnectionId, @@ -434,7 +434,7 @@ impl RemoteWorktree { #[derive(Clone)] pub struct Snapshot { - id: u64, + id: usize, scan_id: usize, abs_path: Arc, root_name: String, @@ -871,7 +871,7 @@ impl BackgroundScanner { snapshot: Arc>, handles: Arc, Weak>>>>, notify: Sender, - worktree_id: u64, + worktree_id: usize, ) -> Self { let mut scanner = Self { root_char_bag: Default::default(), @@ -1411,37 +1411,33 @@ impl WorktreeHandle for ModelHandle { cx.spawn(|cx| async move { let mtime = cx .background_executor() - .spawn(async move { - if let Ok(metadata) = fs::metadata(&abs_path) { - metadata.modified().unwrap() - } else { - UNIX_EPOCH - } - }) - .await; + .spawn(async move { fs::metadata(&abs_path) }) + .await? + .modified()?; let state = handle.read_with(&cx, |tree, _| { let mut handles = tree.as_local().unwrap().handles.lock(); - if let Some(state) = handles.get(&path).and_then(Weak::upgrade) { - state - } else { - let handle_state = if let Some(entry) = tree.entry_for_path(&path) { - FileHandleState { - path: entry.path().clone(), - is_deleted: false, - mtime, - } - } else { - FileHandleState { - path: path.clone(), - is_deleted: !tree.path_is_pending(path), - mtime, - } - }; + handles + .get(&path) + .and_then(Weak::upgrade) + .unwrap_or_else(|| { + let handle_state = if let Some(entry) = tree.entry_for_path(&path) { + FileHandleState { + path: entry.path().clone(), + is_deleted: false, + mtime, + } + } else { + FileHandleState { + path: path.clone(), + is_deleted: !tree.path_is_pending(path), + mtime, + } + }; - let state = Arc::new(Mutex::new(handle_state.clone())); - handles.insert(handle_state.path, Arc::downgrade(&state)); - state - } + let state = Arc::new(Mutex::new(handle_state.clone())); + handles.insert(handle_state.path, Arc::downgrade(&state)); + state + }) }); Ok(FileHandle { worktree: handle.clone(), @@ -1458,7 +1454,7 @@ impl WorktreeHandle for ModelHandle { .request( connection_id, proto::OpenFile { - worktree_id, + worktree_id: worktree_id as u64, path: path.to_string_lossy().to_string(), }, ) @@ -1724,7 +1720,7 @@ mod tests { let buffer = cx.add_model(|cx| Buffer::new(1, "a line of text.\n".repeat(10 * 1024), cx)); - let file = cx.update(|cx| tree.file("", cx)).await; + let file = cx.update(|cx| tree.file("", cx)).await.unwrap(); cx.update(|cx| { assert_eq!(file.path().file_name(), None); smol::block_on(file.save(buffer.read(cx).snapshot().text(), cx.as_ref())).unwrap(); @@ -1751,11 +1747,11 @@ mod tests { })); let tree = cx.add_model(|cx| Worktree::local(dir.path(), cx)); - let file2 = cx.update(|cx| tree.file("a/file2", cx)).await; - let file3 = cx.update(|cx| tree.file("a/file3", cx)).await; - let file4 = cx.update(|cx| tree.file("b/c/file4", cx)).await; - let file5 = cx.update(|cx| tree.file("b/c/file5", cx)).await; - let non_existent_file = cx.update(|cx| tree.file("a/file_x", cx)).await; + let file2 = cx.update(|cx| tree.file("a/file2", cx)).await.unwrap(); + let file3 = cx.update(|cx| tree.file("a/file3", cx)).await.unwrap(); + let file4 = cx.update(|cx| tree.file("b/c/file4", cx)).await.unwrap(); + let file5 = cx.update(|cx| tree.file("b/c/file5", cx)).await.unwrap(); + let non_existent_file = cx.update(|cx| tree.file("a/file_x", cx)).await.unwrap(); // After scanning, the worktree knows which files exist and which don't. cx.read(|cx| tree.read(cx).as_local().unwrap().scan_complete()) diff --git a/zed/src/worktree/fuzzy.rs b/zed/src/worktree/fuzzy.rs index 993031029c..d9d79cc20c 100644 --- a/zed/src/worktree/fuzzy.rs +++ b/zed/src/worktree/fuzzy.rs @@ -22,7 +22,7 @@ pub struct MatchCandidate<'a> { pub struct PathMatch { pub score: f64, pub positions: Vec, - pub tree_id: u64, + pub tree_id: usize, pub path: Arc, pub include_root_name: bool, }