diff --git a/CargoPants.toml b/CargoPants.toml new file mode 120000 index 0000000000..f036ca3dce --- /dev/null +++ b/CargoPants.toml @@ -0,0 +1 @@ +Cargo.toml \ No newline at end of file diff --git a/zed/src/editor/buffer/mod.rs b/zed/src/editor/buffer/mod.rs index bcc6880916..c462472a39 100644 --- a/zed/src/editor/buffer/mod.rs +++ b/zed/src/editor/buffer/mod.rs @@ -351,23 +351,15 @@ pub struct UndoOperation { } impl Buffer { - pub fn new>>( - replica_id: ReplicaId, - base_text: T, - ctx: &mut ModelContext, - ) -> Self { - Self::build(replica_id, History::new(base_text.into()), ctx) + pub fn new>>(replica_id: ReplicaId, base_text: T) -> Self { + Self::build(replica_id, History::new(base_text.into())) } - pub fn from_history( - replica_id: ReplicaId, - history: History, - ctx: &mut ModelContext, - ) -> Self { - Self::build(replica_id, history, ctx) + pub fn from_history(replica_id: ReplicaId, history: History) -> Self { + Self::build(replica_id, history) } - fn build(replica_id: ReplicaId, history: History, _: &mut ModelContext) -> Self { + fn build(replica_id: ReplicaId, history: History) -> Self { let mut insertion_splits = HashMap::default(); let mut fragments = SumTree::new(); @@ -2304,8 +2296,8 @@ mod tests { #[test] fn test_edit() { App::test((), |ctx| { - ctx.add_model(|ctx| { - let mut buffer = Buffer::new(0, "abc", ctx); + ctx.add_model(|_| { + let mut buffer = Buffer::new(0, "abc"); assert_eq!(buffer.text(), "abc"); buffer.edit(vec![3..3], "def", None).unwrap(); assert_eq!(buffer.text(), "abcdef"); @@ -2329,8 +2321,8 @@ mod tests { let buffer_1_events = Rc::new(RefCell::new(Vec::new())); let buffer_2_events = Rc::new(RefCell::new(Vec::new())); - let buffer1 = app.add_model(|ctx| Buffer::new(0, "abcdef", ctx)); - let buffer2 = app.add_model(|ctx| Buffer::new(1, "abcdef", ctx)); + let buffer1 = app.add_model(|_| Buffer::new(0, "abcdef")); + let buffer2 = app.add_model(|_| Buffer::new(1, "abcdef")); let mut buffer_ops = Vec::new(); buffer1.update(app, |buffer, ctx| { let buffer_1_events = buffer_1_events.clone(); @@ -2417,7 +2409,7 @@ mod tests { .take(reference_string_len) .collect::(); ctx.add_model(|ctx| { - let mut buffer = Buffer::new(0, reference_string.as_str(), ctx); + let mut buffer = Buffer::new(0, reference_string.as_str()); let mut buffer_versions = Vec::new(); for _i in 0..10 { let (old_ranges, new_text, _) = buffer.randomly_mutate(rng, None); @@ -2503,7 +2495,7 @@ mod tests { fn test_line_len() { App::test((), |ctx| { ctx.add_model(|ctx| { - let mut buffer = Buffer::new(0, "", ctx); + let mut buffer = Buffer::new(0, ""); buffer.edit(vec![0..0], "abcd\nefg\nhij", None).unwrap(); buffer.edit(vec![12..12], "kl\nmno", None).unwrap(); buffer.edit(vec![18..18], "\npqrs\n", None).unwrap(); @@ -2525,7 +2517,7 @@ mod tests { fn test_rightmost_point() { App::test((), |ctx| { ctx.add_model(|ctx| { - let mut buffer = Buffer::new(0, "", ctx); + let mut buffer = Buffer::new(0, ""); assert_eq!(buffer.rightmost_point().row, 0); buffer.edit(vec![0..0], "abcd\nefg\nhij", None).unwrap(); assert_eq!(buffer.rightmost_point().row, 0); @@ -2546,7 +2538,7 @@ mod tests { fn test_text_summary_for_range() { App::test((), |ctx| { ctx.add_model(|ctx| { - let buffer = Buffer::new(0, "ab\nefg\nhklm\nnopqrs\ntuvwxyz", ctx); + let buffer = Buffer::new(0, "ab\nefg\nhklm\nnopqrs\ntuvwxyz"); let text = Text::from(buffer.text()); assert_eq!( buffer.text_summary_for_range(1..3), @@ -2577,7 +2569,7 @@ mod tests { fn test_chars_at() { App::test((), |ctx| { ctx.add_model(|ctx| { - let mut buffer = Buffer::new(0, "", ctx); + let mut buffer = Buffer::new(0, ""); buffer.edit(vec![0..0], "abcd\nefgh\nij", None).unwrap(); buffer.edit(vec![12..12], "kl\nmno", None).unwrap(); buffer.edit(vec![18..18], "\npqrs", None).unwrap(); @@ -2599,7 +2591,7 @@ mod tests { assert_eq!(chars.collect::(), "PQrs"); // Regression test: - let mut buffer = Buffer::new(0, "", ctx); + let mut buffer = Buffer::new(0, ""); buffer.edit(vec![0..0], "[workspace]\nmembers = [\n \"xray_core\",\n \"xray_server\",\n \"xray_cli\",\n \"xray_wasm\",\n]\n", None).unwrap(); buffer.edit(vec![60..60], "\n", None).unwrap(); @@ -2729,7 +2721,7 @@ mod tests { fn test_anchors() { App::test((), |ctx| { ctx.add_model(|ctx| { - let mut buffer = Buffer::new(0, "", ctx); + let mut buffer = Buffer::new(0, ""); buffer.edit(vec![0..0], "abc", None).unwrap(); let left_anchor = buffer.anchor_before(2).unwrap(); let right_anchor = buffer.anchor_after(2).unwrap(); @@ -2894,7 +2886,7 @@ mod tests { fn test_anchors_at_start_and_end() { App::test((), |ctx| { ctx.add_model(|ctx| { - let mut buffer = Buffer::new(0, "", ctx); + let mut buffer = Buffer::new(0, ""); let before_start_anchor = buffer.anchor_before(0).unwrap(); let after_end_anchor = buffer.anchor_after(0).unwrap(); @@ -2921,7 +2913,7 @@ mod tests { #[test] fn test_is_modified() { App::test((), |app| { - let model = app.add_model(|ctx| Buffer::new(0, "abc", ctx)); + let model = app.add_model(|ctx| Buffer::new(0, "abc")); let events = Rc::new(RefCell::new(Vec::new())); // initially, the buffer isn't dirty. @@ -3009,7 +3001,7 @@ mod tests { fn test_undo_redo() { App::test((), |app| { app.add_model(|ctx| { - let mut buffer = Buffer::new(0, "1234", ctx); + let mut buffer = Buffer::new(0, "1234"); let edit1 = buffer.edit(vec![1..1], "abx", None).unwrap(); let edit2 = buffer.edit(vec![3..4], "yzef", None).unwrap(); @@ -3047,7 +3039,7 @@ mod tests { App::test((), |app| { app.add_model(|ctx| { let mut now = Instant::now(); - let mut buffer = Buffer::new(0, "123456", ctx); + let mut buffer = Buffer::new(0, "123456"); let (set_id, _) = buffer .add_selection_set(buffer.selections_from_ranges(vec![4..4]).unwrap(), None); @@ -3132,7 +3124,7 @@ mod tests { let mut network = Network::new(); for i in 0..PEERS { let buffer = - ctx.add_model(|ctx| Buffer::new(i as ReplicaId, base_text.as_str(), ctx)); + ctx.add_model(|ctx| Buffer::new(i as ReplicaId, base_text.as_str())); buffers.push(buffer); replica_ids.push(i as u16); network.add_peer(i as u16); diff --git a/zed/src/editor/buffer_view.rs b/zed/src/editor/buffer_view.rs index 3b9bee8a2e..dd5c73ba0b 100644 --- a/zed/src/editor/buffer_view.rs +++ b/zed/src/editor/buffer_view.rs @@ -120,7 +120,7 @@ struct ClipboardSelection { impl BufferView { pub fn single_line(settings: watch::Receiver, ctx: &mut ViewContext) -> Self { - let buffer = ctx.add_model(|ctx| Buffer::new(0, String::new(), ctx)); + let buffer = ctx.add_model(|_| Buffer::new(0, String::new())); let mut view = Self::for_buffer(buffer, None, settings, ctx); view.single_line = true; view @@ -1421,8 +1421,7 @@ mod tests { #[test] fn test_selection_with_mouse() { App::test((), |app| { - let buffer = - app.add_model(|ctx| Buffer::new(0, "aaaaaa\nbbbbbb\ncccccc\ndddddd\n", ctx)); + let buffer = app.add_model(|ctx| Buffer::new(0, "aaaaaa\nbbbbbb\ncccccc\ndddddd\n")); let settings = settings::channel(&app.font_cache()).unwrap().1; let (_, buffer_view) = app.add_window(|ctx| BufferView::for_buffer(buffer, None, settings, ctx)); @@ -1536,7 +1535,7 @@ mod tests { let layout_cache = TextLayoutCache::new(app.platform().fonts()); let font_cache = app.font_cache().clone(); - let buffer = app.add_model(|ctx| Buffer::new(0, sample_text(6, 6), ctx)); + let buffer = app.add_model(|_| Buffer::new(0, sample_text(6, 6))); let settings = settings::channel(&font_cache).unwrap().1; let (_, view) = @@ -1553,7 +1552,7 @@ mod tests { #[test] fn test_fold() { App::test((), |app| { - let buffer = app.add_model(|ctx| { + let buffer = app.add_model(|_| { Buffer::new( 0, " @@ -1574,7 +1573,6 @@ mod tests { } " .unindent(), - ctx, ) }); let settings = settings::channel(&app.font_cache()).unwrap().1; @@ -1648,7 +1646,7 @@ mod tests { #[test] fn test_move_cursor() -> Result<()> { App::test((), |app| { - let buffer = app.add_model(|ctx| Buffer::new(0, sample_text(6, 6), ctx)); + let buffer = app.add_model(|_| Buffer::new(0, sample_text(6, 6))); let settings = settings::channel(&app.font_cache()).unwrap().1; let (_, view) = app.add_window(|ctx| BufferView::for_buffer(buffer.clone(), None, settings, ctx)); @@ -1685,12 +1683,8 @@ mod tests { #[test] fn test_backspace() { App::test((), |app| { - let buffer = app.add_model(|ctx| { - Buffer::new( - 0, - "one two three\nfour five six\nseven eight nine\nten\n", - ctx, - ) + let buffer = app.add_model(|_| { + Buffer::new(0, "one two three\nfour five six\nseven eight nine\nten\n") }); let settings = settings::channel(&app.font_cache()).unwrap().1; let (_, view) = @@ -1722,7 +1716,7 @@ mod tests { #[test] fn test_clipboard() { App::test((), |app| { - let buffer = app.add_model(|ctx| Buffer::new(0, "one two three four five six ", ctx)); + let buffer = app.add_model(|_| Buffer::new(0, "one two three four five six ")); let settings = settings::channel(&app.font_cache()).unwrap().1; let view = app .add_window(|ctx| BufferView::for_buffer(buffer.clone(), None, settings, ctx)) diff --git a/zed/src/editor/display_map/fold_map.rs b/zed/src/editor/display_map/fold_map.rs index 536971a87d..3c52adcbaa 100644 --- a/zed/src/editor/display_map/fold_map.rs +++ b/zed/src/editor/display_map/fold_map.rs @@ -471,7 +471,7 @@ mod tests { #[test] fn test_basic_folds() { App::test((), |app| { - let buffer = app.add_model(|ctx| Buffer::new(0, sample_text(5, 6), ctx)); + let buffer = app.add_model(|ctx| Buffer::new(0, sample_text(5, 6))); let mut map = FoldMap::new(buffer.clone(), app.as_ref()); map.fold( @@ -522,7 +522,7 @@ mod tests { #[test] fn test_overlapping_folds() { App::test((), |app| { - let buffer = app.add_model(|ctx| Buffer::new(0, sample_text(5, 6), ctx)); + let buffer = app.add_model(|_| Buffer::new(0, sample_text(5, 6))); let mut map = FoldMap::new(buffer.clone(), app.as_ref()); map.fold( vec![ @@ -541,7 +541,7 @@ mod tests { #[test] fn test_merging_folds_via_edit() { App::test((), |app| { - let buffer = app.add_model(|ctx| Buffer::new(0, sample_text(5, 6), ctx)); + let buffer = app.add_model(|_| Buffer::new(0, sample_text(5, 6))); let mut map = FoldMap::new(buffer.clone(), app.as_ref()); map.fold( @@ -589,10 +589,10 @@ mod tests { let mut rng = StdRng::seed_from_u64(seed); App::test((), |app| { - let buffer = app.add_model(|ctx| { + let buffer = app.add_model(|_| { let len = rng.gen_range(0..10); let text = RandomCharIter::new(&mut rng).take(len).collect::(); - Buffer::new(0, text, ctx) + Buffer::new(0, text) }); let mut map = FoldMap::new(buffer.clone(), app.as_ref()); @@ -664,7 +664,7 @@ mod tests { fn test_buffer_rows() { App::test((), |app| { let text = sample_text(6, 6) + "\n"; - let buffer = app.add_model(|ctx| Buffer::new(0, text, ctx)); + let buffer = app.add_model(|_| Buffer::new(0, text)); let mut map = FoldMap::new(buffer.clone(), app.as_ref()); diff --git a/zed/src/editor/display_map/mod.rs b/zed/src/editor/display_map/mod.rs index c44f3ca302..8142a8925c 100644 --- a/zed/src/editor/display_map/mod.rs +++ b/zed/src/editor/display_map/mod.rs @@ -298,7 +298,7 @@ mod tests { fn test_chars_at() { App::test((), |app| { let text = sample_text(6, 6); - let buffer = app.add_model(|ctx| Buffer::new(0, text, ctx)); + let buffer = app.add_model(|_| Buffer::new(0, text)); let map = app.add_model(|ctx| DisplayMap::new(buffer.clone(), 4, ctx)); buffer .update(app, |buffer, ctx| { @@ -365,7 +365,7 @@ mod tests { #[test] fn test_max_point() { App::test((), |app| { - let buffer = app.add_model(|ctx| Buffer::new(0, "aaa\n\t\tbbb", ctx)); + let buffer = app.add_model(|_| Buffer::new(0, "aaa\n\t\tbbb")); let map = app.add_model(|ctx| DisplayMap::new(buffer.clone(), 4, ctx)); assert_eq!( map.read(app).max_point(app.as_ref()), diff --git a/zed/src/workspace/workspace.rs b/zed/src/workspace/workspace.rs index 75bec37eb8..212682ffce 100644 --- a/zed/src/workspace/workspace.rs +++ b/zed/src/workspace/workspace.rs @@ -1,14 +1,16 @@ use super::{ItemView, ItemViewHandle}; use crate::{ - editor::{Buffer, History}, + editor::{Buffer, BufferView, History}, settings::Settings, time::ReplicaId, watch, worktree::{FileHandle, Worktree, WorktreeHandle as _}, }; use anyhow::anyhow; +use futures_core::future::LocalBoxFuture; use gpui::{AppContext, Entity, Handle, ModelContext, ModelHandle, MutableAppContext, ViewContext}; use smol::prelude::*; +use std::{collections::hash_map::Entry, future}; use std::{ collections::{HashMap, HashSet}, fmt::Debug, @@ -82,14 +84,19 @@ pub struct Workspace { replica_id: ReplicaId, worktrees: HashSet>, items: HashMap<(usize, u64), OpenedItem>, + buffers: HashMap< + (usize, u64), + postage::watch::Receiver, Arc>>>, + >, } impl Workspace { pub fn new(paths: Vec, ctx: &mut ModelContext) -> Self { let mut workspace = Self { replica_id: 0, - worktrees: HashSet::new(), - items: HashMap::new(), + worktrees: Default::default(), + items: Default::default(), + buffers: Default::default(), }; workspace.open_paths(&paths, ctx); workspace @@ -149,6 +156,78 @@ impl Workspace { (worktree_id, Path::new("").into()) } + pub fn open_entry2( + &mut self, + (worktree_id, path): (usize, Arc), + window_id: usize, + settings: watch::Receiver, + ctx: &mut ModelContext, + ) -> LocalBoxFuture<'static, Result, Arc>> { + let worktree = match self.worktrees.get(&worktree_id).cloned() { + Some(worktree) => worktree, + None => { + return future::ready(Err(Arc::new(anyhow!( + "worktree {} does not exist", + worktree_id + )))) + .boxed_local(); + } + }; + + let inode = match worktree.read(ctx).inode_for_path(&path) { + Some(inode) => inode, + None => { + return future::ready(Err(Arc::new(anyhow!("path {:?} does not exist", path)))) + .boxed_local(); + } + }; + + let file = match worktree.file(path.clone(), ctx.as_ref()) { + Some(file) => file, + None => { + return future::ready(Err(Arc::new(anyhow!("path {:?} does not exist", path)))) + .boxed_local() + } + }; + + if let Entry::Vacant(entry) = self.buffers.entry((worktree_id, inode)) { + let (mut tx, rx) = postage::watch::channel(); + entry.insert(rx); + let history = file.load_history(ctx.as_ref()); + let replica_id = self.replica_id; + let buffer = ctx + .background_executor() + .spawn(async move { Ok(Buffer::from_history(replica_id, history.await?)) }); + ctx.spawn(buffer, move |_, from_history_result, ctx| { + *tx.borrow_mut() = Some(match from_history_result { + Ok(buffer) => Ok(ctx.add_model(|_| buffer)), + Err(error) => Err(Arc::new(error)), + }) + }) + .detach() + } + + let mut watch = self.buffers.get(&(worktree_id, inode)).unwrap().clone(); + ctx.spawn( + async move { + loop { + if let Some(load_result) = watch.borrow().as_ref() { + return load_result.clone(); + } + watch.next().await; + } + }, + move |_, load_result, ctx| { + load_result.map(|buffer_handle| { + Box::new(ctx.as_mut().add_view(window_id, |ctx| { + BufferView::for_buffer(buffer_handle, Some(file), settings, ctx) + })) as Box + }) + }, + ) + .boxed_local() + } + pub fn open_entry( &mut self, (worktree_id, path): (usize, Arc), @@ -165,7 +244,9 @@ impl Workspace { .inode_for_path(&path) .ok_or_else(|| anyhow!("path {:?} does not exist", path))?; - let file = worktree.file(path.clone(), ctx.as_ref())?; + let file = worktree + .file(path.clone(), ctx.as_ref()) + .ok_or_else(|| anyhow!("path {:?} does not exist", path))?; let item_key = (worktree_id, inode); if let Some(item) = self.items.get(&item_key).cloned() { @@ -195,9 +276,9 @@ impl Workspace { history, move |me, history: anyhow::Result, ctx| match history { Ok(history) => { - let handle = Box::new( - ctx.add_model(|ctx| Buffer::from_history(replica_id, history, ctx)), - ) as Box; + let handle = + Box::new(ctx.add_model(|_| Buffer::from_history(replica_id, history))) + as Box; me.items .insert(item_key, OpenedItem::Loaded(handle.clone())); ctx.spawn( diff --git a/zed/src/workspace/workspace_view.rs b/zed/src/workspace/workspace_view.rs index 3e54a5d998..8ac38ade12 100644 --- a/zed/src/workspace/workspace_view.rs +++ b/zed/src/workspace/workspace_view.rs @@ -243,30 +243,18 @@ impl WorkspaceView { self.loading_entries.insert(entry.clone()); - match self.workspace.update(ctx, |workspace, ctx| { - workspace.open_entry(entry.clone(), ctx) - }) { - Err(error) => { - error!("{}", error); - None + let window_id = ctx.window_id(); + let future = self.workspace.update(ctx, |workspace, ctx| { + workspace.open_entry2(entry.clone(), window_id, self.settings.clone(), ctx) + }); + + Some(ctx.spawn(future, move |me, item_view, ctx| { + me.loading_entries.remove(&entry); + match item_view { + Ok(item_view) => me.add_item(item_view, ctx), + Err(error) => log::error!("error opening item: {}", error), } - Ok(future) => { - let settings = self.settings.clone(); - Some(ctx.spawn(future, move |me, (item, file), ctx| { - me.loading_entries.remove(&entry); - match item { - Ok(item) => { - let item_view = - item.add_view(ctx.window_id(), settings, Some(file), ctx.as_mut()); - me.add_item(item_view, ctx); - } - Err(error) => { - error!("{}", error); - } - } - })) - } - } + })) } pub fn save_active_item(&mut self, _: &(), ctx: &mut ViewContext) { diff --git a/zed/src/worktree.rs b/zed/src/worktree.rs index e945fbb876..58b209cb8c 100644 --- a/zed/src/worktree.rs +++ b/zed/src/worktree.rs @@ -7,7 +7,7 @@ use crate::{ sum_tree::{self, Cursor, Edit, SeekBias, SumTree}, }; use ::ignore::gitignore::Gitignore; -use anyhow::{anyhow, Context, Result}; +use anyhow::{Context, Result}; pub use fuzzy::{match_paths, PathMatch}; use gpui::{scoped_pool, AppContext, Entity, ModelContext, ModelHandle, Task, View, ViewContext}; use lazy_static::lazy_static; @@ -1126,15 +1126,14 @@ struct UpdateIgnoreStatusJob { } pub trait WorktreeHandle { - fn file(&self, path: impl AsRef, app: &AppContext) -> Result; + fn file(&self, path: impl AsRef, app: &AppContext) -> Option; } impl WorktreeHandle for ModelHandle { - fn file(&self, path: impl AsRef, app: &AppContext) -> Result { + fn file(&self, path: impl AsRef, app: &AppContext) -> Option { let tree = self.read(app); - let entry = tree - .entry_for_path(&path) - .ok_or_else(|| anyhow!("path does not exist in tree"))?; + let entry = tree.entry_for_path(&path)?; + let path = entry.path().clone(); let mut handles = tree.handles.lock(); let state = if let Some(state) = handles.get(&path).and_then(Weak::upgrade) { @@ -1148,7 +1147,7 @@ impl WorktreeHandle for ModelHandle { state }; - Ok(FileHandle { + Some(FileHandle { worktree: self.clone(), state, }) @@ -1347,8 +1346,7 @@ mod tests { app.read(|ctx| tree.read(ctx).scan_complete()).await; app.read(|ctx| assert_eq!(tree.read(ctx).file_count(), 1)); - let buffer = - app.add_model(|ctx| Buffer::new(1, "a line of text.\n".repeat(10 * 1024), ctx)); + let buffer = app.add_model(|_| Buffer::new(1, "a line of text.\n".repeat(10 * 1024))); let path = tree.update(&mut app, |tree, ctx| { let path = tree.files(0).next().unwrap().path().clone();