Make Workspace::open_entry2, which returns a dyn ItemViewHandle

Nathan Sobo and Max Brunsfeld created

Co-Authored-By: Max Brunsfeld <maxbrunsfeld@gmail.com>

Change summary

CargoPants.toml                        |  1 
zed/src/editor/buffer/mod.rs           | 50 ++++++--------
zed/src/editor/buffer_view.rs          | 22 ++----
zed/src/editor/display_map/fold_map.rs | 12 +-
zed/src/editor/display_map/mod.rs      |  4 
zed/src/workspace/workspace.rs         | 95 +++++++++++++++++++++++++--
zed/src/workspace/workspace_view.rs    | 34 +++------
zed/src/worktree.rs                    | 16 ++--
8 files changed, 144 insertions(+), 90 deletions(-)

Detailed changes

zed/src/editor/buffer/mod.rs 🔗

@@ -351,23 +351,15 @@ pub struct UndoOperation {
 }
 
 impl Buffer {
-    pub fn new<T: Into<Arc<str>>>(
-        replica_id: ReplicaId,
-        base_text: T,
-        ctx: &mut ModelContext<Self>,
-    ) -> Self {
-        Self::build(replica_id, History::new(base_text.into()), ctx)
+    pub fn new<T: Into<Arc<str>>>(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 {
-        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>) -> 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::<String>();
                 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::<String>(), "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);

zed/src/editor/buffer_view.rs 🔗

@@ -120,7 +120,7 @@ struct ClipboardSelection {
 
 impl BufferView {
     pub fn single_line(settings: watch::Receiver<Settings>, ctx: &mut ViewContext<Self>) -> 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))

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::<String>();
-                    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());
 

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()),

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<ModelHandle<Worktree>>,
     items: HashMap<(usize, u64), OpenedItem>,
+    buffers: HashMap<
+        (usize, u64),
+        postage::watch::Receiver<Option<Result<ModelHandle<Buffer>, Arc<anyhow::Error>>>>,
+    >,
 }
 
 impl Workspace {
     pub fn new(paths: Vec<PathBuf>, ctx: &mut ModelContext<Self>) -> 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<Path>),
+        window_id: usize,
+        settings: watch::Receiver<Settings>,
+        ctx: &mut ModelContext<Self>,
+    ) -> LocalBoxFuture<'static, Result<Box<dyn ItemViewHandle>, Arc<anyhow::Error>>> {
+        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<dyn ItemViewHandle>
+                })
+            },
+        )
+        .boxed_local()
+    }
+
     pub fn open_entry(
         &mut self,
         (worktree_id, path): (usize, Arc<Path>),
@@ -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<History>, ctx| match history {
                 Ok(history) => {
-                    let handle = Box::new(
-                        ctx.add_model(|ctx| Buffer::from_history(replica_id, history, ctx)),
-                    ) as Box<dyn ItemHandle>;
+                    let handle =
+                        Box::new(ctx.add_model(|_| Buffer::from_history(replica_id, history)))
+                            as Box<dyn ItemHandle>;
                     me.items
                         .insert(item_key, OpenedItem::Loaded(handle.clone()));
                     ctx.spawn(

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
-            }
-            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);
-                        }
-                    }
-                }))
+        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),
             }
-        }
+        }))
     }
 
     pub fn save_active_item(&mut self, _: &(), ctx: &mut ViewContext<Self>) {

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<Path>, app: &AppContext) -> Result<FileHandle>;
+    fn file(&self, path: impl AsRef<Path>, app: &AppContext) -> Option<FileHandle>;
 }
 
 impl WorktreeHandle for ModelHandle<Worktree> {
-    fn file(&self, path: impl AsRef<Path>, app: &AppContext) -> Result<FileHandle> {
+    fn file(&self, path: impl AsRef<Path>, app: &AppContext) -> Option<FileHandle> {
         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<Worktree> {
             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();