From bc4f5af0887d45fa8d51b14c7794bd1e48888d09 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 28 May 2021 14:59:24 -0700 Subject: [PATCH] Rename context parameters to `cx` in workspace.rs --- zed/src/workspace.rs | 642 +++++++++++++++++++++---------------------- 1 file changed, 319 insertions(+), 323 deletions(-) diff --git a/zed/src/workspace.rs b/zed/src/workspace.rs index 552ee24d26..36ef65b174 100644 --- a/zed/src/workspace.rs +++ b/zed/src/workspace.rs @@ -26,18 +26,18 @@ use std::{ sync::Arc, }; -pub fn init(app: &mut MutableAppContext) { - app.add_global_action("workspace:open", open); - app.add_global_action("workspace:open_paths", open_paths); - app.add_global_action("app:quit", quit); - app.add_action("workspace:save", Workspace::save_active_item); - app.add_action("workspace:debug_elements", Workspace::debug_elements); - app.add_action("workspace:new_file", Workspace::open_new_file); - app.add_bindings(vec![ +pub fn init(cx: &mut MutableAppContext) { + cx.add_global_action("workspace:open", open); + cx.add_global_action("workspace:open_paths", open_paths); + cx.add_global_action("app:quit", quit); + cx.add_action("workspace:save", Workspace::save_active_item); + cx.add_action("workspace:debug_elements", Workspace::debug_elements); + cx.add_action("workspace:new_file", Workspace::open_new_file); + cx.add_bindings(vec![ Binding::new("cmd-s", "workspace:save", None), Binding::new("cmd-alt-i", "workspace:debug_elements", None), ]); - pane::init(app); + pane::init(cx); } pub struct OpenParams { @@ -45,32 +45,32 @@ pub struct OpenParams { pub app_state: AppState, } -fn open(app_state: &AppState, ctx: &mut MutableAppContext) { +fn open(app_state: &AppState, cx: &mut MutableAppContext) { let app_state = app_state.clone(); - ctx.prompt_for_paths( + cx.prompt_for_paths( PathPromptOptions { files: true, directories: true, multiple: true, }, - move |paths, ctx| { + move |paths, cx| { if let Some(paths) = paths { - ctx.dispatch_global_action("workspace:open_paths", OpenParams { paths, app_state }); + cx.dispatch_global_action("workspace:open_paths", OpenParams { paths, app_state }); } }, ); } -fn open_paths(params: &OpenParams, app: &mut MutableAppContext) { +fn open_paths(params: &OpenParams, cx: &mut MutableAppContext) { log::info!("open paths {:?}", params.paths); // Open paths in existing workspace if possible - for window_id in app.window_ids().collect::>() { - if let Some(handle) = app.root_view::(window_id) { - if handle.update(app, |view, ctx| { - if view.contains_paths(¶ms.paths, ctx.as_ref()) { - let open_paths = view.open_paths(¶ms.paths, ctx); - ctx.foreground().spawn(open_paths).detach(); + for window_id in cx.window_ids().collect::>() { + if let Some(handle) = cx.root_view::(window_id) { + if handle.update(cx, |view, cx| { + if view.contains_paths(¶ms.paths, cx.as_ref()) { + let open_paths = view.open_paths(¶ms.paths, cx); + cx.foreground().spawn(open_paths).detach(); log::info!("open paths on existing workspace"); true } else { @@ -85,21 +85,21 @@ fn open_paths(params: &OpenParams, app: &mut MutableAppContext) { log::info!("open new workspace"); // Add a new workspace if necessary - app.add_window(|ctx| { + cx.add_window(|cx| { let mut view = Workspace::new( 0, params.app_state.settings.clone(), params.app_state.language_registry.clone(), - ctx, + cx, ); - let open_paths = view.open_paths(¶ms.paths, ctx); - ctx.foreground().spawn(open_paths).detach(); + let open_paths = view.open_paths(¶ms.paths, cx); + cx.foreground().spawn(open_paths).detach(); view }); } -fn quit(_: &(), app: &mut MutableAppContext) { - app.platform().quit(); +fn quit(_: &(), cx: &mut MutableAppContext) { + cx.platform().quit(); } pub trait Item: Entity + Sized { @@ -108,15 +108,15 @@ pub trait Item: Entity + Sized { fn build_view( handle: ModelHandle, settings: watch::Receiver, - ctx: &mut ViewContext, + cx: &mut ViewContext, ) -> Self::View; fn file(&self) -> Option<&FileHandle>; } pub trait ItemView: View { - fn title(&self, app: &AppContext) -> String; - fn entry_id(&self, app: &AppContext) -> Option<(usize, Arc)>; + fn title(&self, cx: &AppContext) -> String; + fn entry_id(&self, cx: &AppContext) -> Option<(usize, Arc)>; fn clone_on_split(&self, _: &mut ViewContext) -> Option where Self: Sized, @@ -148,30 +148,30 @@ pub trait ItemHandle: Send + Sync { } pub trait WeakItemHandle: Send + Sync { - fn file<'a>(&'a self, ctx: &'a AppContext) -> Option<&'a FileHandle>; + fn file<'a>(&'a self, cx: &'a AppContext) -> Option<&'a FileHandle>; fn add_view( &self, window_id: usize, settings: watch::Receiver, - app: &mut MutableAppContext, + cx: &mut MutableAppContext, ) -> Option>; - fn alive(&self, ctx: &AppContext) -> bool; + fn alive(&self, cx: &AppContext) -> bool; } pub trait ItemViewHandle: Send + Sync { - fn title(&self, app: &AppContext) -> String; - fn entry_id(&self, app: &AppContext) -> Option<(usize, Arc)>; + fn title(&self, cx: &AppContext) -> String; + fn entry_id(&self, cx: &AppContext) -> Option<(usize, Arc)>; fn boxed_clone(&self) -> Box; - fn clone_on_split(&self, app: &mut MutableAppContext) -> Option>; - fn set_parent_pane(&self, pane: &ViewHandle, app: &mut MutableAppContext); + fn clone_on_split(&self, cx: &mut MutableAppContext) -> Option>; + fn set_parent_pane(&self, pane: &ViewHandle, cx: &mut MutableAppContext); fn id(&self) -> usize; fn to_any(&self) -> AnyViewHandle; - fn is_dirty(&self, ctx: &AppContext) -> bool; - fn has_conflict(&self, ctx: &AppContext) -> bool; + fn is_dirty(&self, cx: &AppContext) -> bool; + fn has_conflict(&self, cx: &AppContext) -> bool; fn save( &self, file: Option, - ctx: &mut MutableAppContext, + cx: &mut MutableAppContext, ) -> Task>; } @@ -186,61 +186,61 @@ impl ItemHandle for ModelHandle { } impl WeakItemHandle for WeakModelHandle { - fn file<'a>(&'a self, ctx: &'a AppContext) -> Option<&'a FileHandle> { - self.upgrade(ctx).and_then(|h| h.read(ctx).file()) + fn file<'a>(&'a self, cx: &'a AppContext) -> Option<&'a FileHandle> { + self.upgrade(cx).and_then(|h| h.read(cx).file()) } fn add_view( &self, window_id: usize, settings: watch::Receiver, - ctx: &mut MutableAppContext, + cx: &mut MutableAppContext, ) -> Option> { - if let Some(handle) = self.upgrade(ctx.as_ref()) { - Some(Box::new(ctx.add_view(window_id, |ctx| { - T::build_view(handle, settings, ctx) + if let Some(handle) = self.upgrade(cx.as_ref()) { + Some(Box::new(cx.add_view(window_id, |cx| { + T::build_view(handle, settings, cx) }))) } else { None } } - fn alive(&self, ctx: &AppContext) -> bool { - self.upgrade(ctx).is_some() + fn alive(&self, cx: &AppContext) -> bool { + self.upgrade(cx).is_some() } } impl ItemViewHandle for ViewHandle { - fn title(&self, app: &AppContext) -> String { - self.read(app).title(app) + fn title(&self, cx: &AppContext) -> String { + self.read(cx).title(cx) } - fn entry_id(&self, app: &AppContext) -> Option<(usize, Arc)> { - self.read(app).entry_id(app) + fn entry_id(&self, cx: &AppContext) -> Option<(usize, Arc)> { + self.read(cx).entry_id(cx) } fn boxed_clone(&self) -> Box { Box::new(self.clone()) } - fn clone_on_split(&self, app: &mut MutableAppContext) -> Option> { - self.update(app, |item, ctx| { - ctx.add_option_view(|ctx| item.clone_on_split(ctx)) + fn clone_on_split(&self, cx: &mut MutableAppContext) -> Option> { + self.update(cx, |item, cx| { + cx.add_option_view(|cx| item.clone_on_split(cx)) }) .map(|handle| Box::new(handle) as Box) } - fn set_parent_pane(&self, pane: &ViewHandle, app: &mut MutableAppContext) { - pane.update(app, |_, ctx| { - ctx.subscribe_to_view(self, |pane, item, event, ctx| { + fn set_parent_pane(&self, pane: &ViewHandle, cx: &mut MutableAppContext) { + pane.update(cx, |_, cx| { + cx.subscribe_to_view(self, |pane, item, event, cx| { if T::should_activate_item_on_event(event) { if let Some(ix) = pane.item_index(&item) { - pane.activate_item(ix, ctx); - pane.activate(ctx); + pane.activate_item(ix, cx); + pane.activate(cx); } } if T::should_update_tab_on_event(event) { - ctx.notify() + cx.notify() } }) }) @@ -249,17 +249,17 @@ impl ItemViewHandle for ViewHandle { fn save( &self, file: Option, - ctx: &mut MutableAppContext, + cx: &mut MutableAppContext, ) -> Task> { - self.update(ctx, |item, ctx| item.save(file, ctx)) + self.update(cx, |item, cx| item.save(file, cx)) } - fn is_dirty(&self, ctx: &AppContext) -> bool { - self.read(ctx).is_dirty(ctx) + fn is_dirty(&self, cx: &AppContext) -> bool { + self.read(cx).is_dirty(cx) } - fn has_conflict(&self, ctx: &AppContext) -> bool { - self.read(ctx).has_conflict(ctx) + fn has_conflict(&self, cx: &AppContext) -> bool { + self.read(cx).has_conflict(cx) } fn id(&self) -> usize { @@ -310,14 +310,14 @@ impl Workspace { replica_id: ReplicaId, settings: watch::Receiver, language_registry: Arc, - ctx: &mut ViewContext, + cx: &mut ViewContext, ) -> Self { - let pane = ctx.add_view(|_| Pane::new(settings.clone())); + let pane = cx.add_view(|_| Pane::new(settings.clone())); let pane_id = pane.id(); - ctx.subscribe_to_view(&pane, move |me, _, event, ctx| { - me.handle_pane_event(pane_id, event, ctx) + cx.subscribe_to_view(&pane, move |me, _, event, cx| { + me.handle_pane_event(pane_id, event, cx) }); - ctx.focus(&pane); + cx.focus(&pane); Workspace { modal: None, @@ -337,21 +337,21 @@ impl Workspace { &self.worktrees } - pub fn contains_paths(&self, paths: &[PathBuf], app: &AppContext) -> bool { - paths.iter().all(|path| self.contains_path(&path, app)) + pub fn contains_paths(&self, paths: &[PathBuf], cx: &AppContext) -> bool { + paths.iter().all(|path| self.contains_path(&path, cx)) } - pub fn contains_path(&self, path: &Path, app: &AppContext) -> bool { + pub fn contains_path(&self, path: &Path, cx: &AppContext) -> bool { self.worktrees .iter() - .any(|worktree| worktree.read(app).contains_abs_path(path)) + .any(|worktree| worktree.read(cx).contains_abs_path(path)) } - pub fn worktree_scans_complete(&self, ctx: &AppContext) -> impl Future + 'static { + pub fn worktree_scans_complete(&self, cx: &AppContext) -> impl Future + 'static { let futures = self .worktrees .iter() - .map(|worktree| worktree.read(ctx).scan_complete()) + .map(|worktree| worktree.read(cx).scan_complete()) .collect::>(); async move { for future in futures { @@ -363,27 +363,27 @@ impl Workspace { pub fn open_paths( &mut self, abs_paths: &[PathBuf], - ctx: &mut ViewContext, + cx: &mut ViewContext, ) -> impl Future { let entries = abs_paths .iter() .cloned() - .map(|path| self.file_for_path(&path, ctx)) + .map(|path| self.file_for_path(&path, cx)) .collect::>(); - let bg = ctx.background_executor().clone(); + let bg = cx.background_executor().clone(); let tasks = abs_paths .iter() .cloned() .zip(entries.into_iter()) .map(|(abs_path, file)| { let is_file = bg.spawn(async move { abs_path.is_file() }); - ctx.spawn(|this, mut ctx| async move { + cx.spawn(|this, mut cx| async move { let file = file.await; let is_file = is_file.await; - this.update(&mut ctx, |this, ctx| { + this.update(&mut cx, |this, cx| { if is_file { - this.open_entry(file.entry_id(), ctx) + this.open_entry(file.entry_id(), cx) } else { None } @@ -400,74 +400,74 @@ impl Workspace { } } - fn file_for_path(&mut self, abs_path: &Path, ctx: &mut ViewContext) -> Task { + fn file_for_path(&mut self, abs_path: &Path, cx: &mut ViewContext) -> Task { for tree in self.worktrees.iter() { - if let Ok(relative_path) = abs_path.strip_prefix(tree.read(ctx).abs_path()) { - return tree.file(relative_path, ctx.as_mut()); + if let Ok(relative_path) = abs_path.strip_prefix(tree.read(cx).abs_path()) { + return tree.file(relative_path, cx.as_mut()); } } - let worktree = self.add_worktree(&abs_path, ctx); - worktree.file(Path::new(""), ctx.as_mut()) + let worktree = self.add_worktree(&abs_path, cx); + worktree.file(Path::new(""), cx.as_mut()) } pub fn add_worktree( &mut self, path: &Path, - ctx: &mut ViewContext, + cx: &mut ViewContext, ) -> ModelHandle { - let worktree = ctx.add_model(|ctx| Worktree::new(path, ctx)); - ctx.observe_model(&worktree, |_, _, ctx| ctx.notify()); + let worktree = cx.add_model(|cx| Worktree::new(path, cx)); + cx.observe_model(&worktree, |_, _, cx| cx.notify()); self.worktrees.insert(worktree.clone()); - ctx.notify(); + cx.notify(); worktree } - pub fn toggle_modal(&mut self, ctx: &mut ViewContext, add_view: F) + pub fn toggle_modal(&mut self, cx: &mut ViewContext, add_view: F) where V: 'static + View, F: FnOnce(&mut ViewContext, &mut Self) -> ViewHandle, { if self.modal.as_ref().map_or(false, |modal| modal.is::()) { self.modal.take(); - ctx.focus_self(); + cx.focus_self(); } else { - let modal = add_view(ctx, self); - ctx.focus(&modal); + let modal = add_view(cx, self); + cx.focus(&modal); self.modal = Some(modal.into()); } - ctx.notify(); + cx.notify(); } pub fn modal(&self) -> Option<&AnyViewHandle> { self.modal.as_ref() } - pub fn dismiss_modal(&mut self, ctx: &mut ViewContext) { + pub fn dismiss_modal(&mut self, cx: &mut ViewContext) { if self.modal.take().is_some() { - ctx.focus(&self.active_pane); - ctx.notify(); + cx.focus(&self.active_pane); + cx.notify(); } } - pub fn open_new_file(&mut self, _: &(), ctx: &mut ViewContext) { - let buffer = ctx.add_model(|ctx| Buffer::new(self.replica_id, "", ctx)); + pub fn open_new_file(&mut self, _: &(), cx: &mut ViewContext) { + let buffer = cx.add_model(|cx| Buffer::new(self.replica_id, "", cx)); let buffer_view = - ctx.add_view(|ctx| Editor::for_buffer(buffer.clone(), self.settings.clone(), ctx)); + cx.add_view(|cx| Editor::for_buffer(buffer.clone(), self.settings.clone(), cx)); self.items.push(ItemHandle::downgrade(&buffer)); - self.add_item_view(Box::new(buffer_view), ctx); + self.add_item_view(Box::new(buffer_view), cx); } #[must_use] pub fn open_entry( &mut self, entry: (usize, Arc), - ctx: &mut ViewContext, + cx: &mut ViewContext, ) -> Option> { // If the active pane contains a view for this file, then activate // that item view. if self .active_pane() - .update(ctx, |pane, ctx| pane.activate_entry(entry.clone(), ctx)) + .update(cx, |pane, cx| pane.activate_entry(entry.clone(), cx)) { return None; } @@ -477,14 +477,14 @@ impl Workspace { let settings = self.settings.clone(); let mut view_for_existing_item = None; self.items.retain(|item| { - if item.alive(ctx.as_ref()) { + if item.alive(cx.as_ref()) { if view_for_existing_item.is_none() && item - .file(ctx.as_ref()) + .file(cx.as_ref()) .map_or(false, |f| f.entry_id() == entry) { view_for_existing_item = Some( - item.add_view(ctx.window_id(), settings.clone(), ctx.as_mut()) + item.add_view(cx.window_id(), settings.clone(), cx.as_mut()) .unwrap(), ); } @@ -494,7 +494,7 @@ impl Workspace { } }); if let Some(view) = view_for_existing_item { - self.add_item_view(view, ctx); + self.add_item_view(view, cx); return None; } @@ -508,28 +508,28 @@ impl Workspace { } }; - let file = worktree.file(path.clone(), ctx.as_mut()); + let file = worktree.file(path.clone(), cx.as_mut()); if let Entry::Vacant(entry) = self.loading_items.entry(entry.clone()) { let (mut tx, rx) = postage::watch::channel(); entry.insert(rx); let replica_id = self.replica_id; let language_registry = self.language_registry.clone(); - ctx.as_mut() - .spawn(|mut ctx| async move { + cx.as_mut() + .spawn(|mut cx| async move { let file = file.await; - let history = ctx.read(|ctx| file.load_history(ctx)); - let history = ctx.background_executor().spawn(history).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(ctx.add_model(|ctx| { + Ok(history) => Ok(Box::new(cx.add_model(|cx| { let language = language_registry.select_language(path); Buffer::from_history( replica_id, history, Some(file), language.cloned(), - ctx, + cx, ) }))), Err(error) => Err(Arc::new(error)), @@ -540,7 +540,7 @@ impl Workspace { let mut watch = self.loading_items.get(&entry).unwrap().clone(); - Some(ctx.spawn(|this, mut ctx| async move { + Some(cx.spawn(|this, mut cx| async move { let load_result = loop { if let Some(load_result) = watch.borrow().as_ref() { break load_result.clone(); @@ -548,16 +548,16 @@ impl Workspace { watch.next().await; }; - this.update(&mut ctx, |this, ctx| { + this.update(&mut cx, |this, cx| { this.loading_items.remove(&entry); match load_result { Ok(item) => { let weak_item = item.downgrade(); let view = weak_item - .add_view(ctx.window_id(), settings, ctx.as_mut()) + .add_view(cx.window_id(), settings, cx.as_mut()) .unwrap(); this.items.push(weak_item); - this.add_item_view(view, ctx); + this.add_item_view(view, cx); } Err(error) => { log::error!("error opening item: {}", error); @@ -567,27 +567,27 @@ impl Workspace { })) } - pub fn active_item(&self, ctx: &ViewContext) -> Option> { - self.active_pane().read(ctx).active_item() + pub fn active_item(&self, cx: &ViewContext) -> Option> { + self.active_pane().read(cx).active_item() } - pub fn save_active_item(&mut self, _: &(), ctx: &mut ViewContext) { - if let Some(item) = self.active_item(ctx) { - let handle = ctx.handle(); - if item.entry_id(ctx.as_ref()).is_none() { + pub fn save_active_item(&mut self, _: &(), cx: &mut ViewContext) { + if let Some(item) = self.active_item(cx) { + let handle = cx.handle(); + if item.entry_id(cx.as_ref()).is_none() { let start_path = self .worktrees .iter() .next() - .map_or(Path::new(""), |h| h.read(ctx).abs_path()) + .map_or(Path::new(""), |h| h.read(cx).abs_path()) .to_path_buf(); - ctx.prompt_for_new_path(&start_path, move |path, ctx| { + cx.prompt_for_new_path(&start_path, move |path, cx| { if let Some(path) = path { - ctx.spawn(|mut ctx| async move { + cx.spawn(|mut cx| async move { let file = handle - .update(&mut ctx, |me, ctx| me.file_for_path(&path, ctx)) + .update(&mut cx, |me, cx| me.file_for_path(&path, cx)) .await; - if let Err(error) = ctx.update(|ctx| item.save(Some(file), ctx)).await { + if let Err(error) = cx.update(|cx| item.save(Some(file), cx)).await { error!("failed to save item: {:?}, ", error); } }) @@ -595,17 +595,17 @@ impl Workspace { } }); return; - } else if item.has_conflict(ctx.as_ref()) { + } else if item.has_conflict(cx.as_ref()) { const CONFLICT_MESSAGE: &'static str = "This file has changed on disk since you started editing it. Do you want to overwrite it?"; - ctx.prompt( + cx.prompt( PromptLevel::Warning, CONFLICT_MESSAGE, &["Overwrite", "Cancel"], - move |answer, ctx| { + move |answer, cx| { if answer == 0 { - ctx.spawn(|mut ctx| async move { - if let Err(error) = ctx.update(|ctx| item.save(None, ctx)).await { + cx.spawn(|mut cx| async move { + if let Err(error) = cx.update(|cx| item.save(None, cx)).await { error!("failed to save item: {:?}, ", error); } }) @@ -614,8 +614,8 @@ impl Workspace { }, ); } else { - ctx.spawn(|_, mut ctx| async move { - if let Err(error) = ctx.update(|ctx| item.save(None, ctx)).await { + cx.spawn(|_, mut cx| async move { + if let Err(error) = cx.update(|cx| item.save(None, cx)).await { error!("failed to save item: {:?}, ", error); } }) @@ -624,11 +624,11 @@ impl Workspace { } } - pub fn debug_elements(&mut self, _: &(), ctx: &mut ViewContext) { - match to_string_pretty(&ctx.debug_elements()) { + pub fn debug_elements(&mut self, _: &(), cx: &mut ViewContext) { + match to_string_pretty(&cx.debug_elements()) { Ok(json) => { let kib = json.len() as f32 / 1024.; - ctx.as_mut().write_to_clipboard(ClipboardItem::new(json)); + cx.as_mut().write_to_clipboard(ClipboardItem::new(json)); log::info!( "copied {:.1} KiB of element debug JSON to the clipboard", kib @@ -640,39 +640,39 @@ impl Workspace { }; } - fn add_pane(&mut self, ctx: &mut ViewContext) -> ViewHandle { - let pane = ctx.add_view(|_| Pane::new(self.settings.clone())); + fn add_pane(&mut self, cx: &mut ViewContext) -> ViewHandle { + let pane = cx.add_view(|_| Pane::new(self.settings.clone())); let pane_id = pane.id(); - ctx.subscribe_to_view(&pane, move |me, _, event, ctx| { - me.handle_pane_event(pane_id, event, ctx) + cx.subscribe_to_view(&pane, move |me, _, event, cx| { + me.handle_pane_event(pane_id, event, cx) }); self.panes.push(pane.clone()); - self.activate_pane(pane.clone(), ctx); + self.activate_pane(pane.clone(), cx); pane } - fn activate_pane(&mut self, pane: ViewHandle, ctx: &mut ViewContext) { + fn activate_pane(&mut self, pane: ViewHandle, cx: &mut ViewContext) { self.active_pane = pane; - ctx.focus(&self.active_pane); - ctx.notify(); + cx.focus(&self.active_pane); + cx.notify(); } fn handle_pane_event( &mut self, pane_id: usize, event: &pane::Event, - ctx: &mut ViewContext, + cx: &mut ViewContext, ) { if let Some(pane) = self.pane(pane_id) { match event { pane::Event::Split(direction) => { - self.split_pane(pane, *direction, ctx); + self.split_pane(pane, *direction, cx); } pane::Event::Remove => { - self.remove_pane(pane, ctx); + self.remove_pane(pane, cx); } pane::Event::Activate => { - self.activate_pane(pane, ctx); + self.activate_pane(pane, cx); } } } else { @@ -684,26 +684,26 @@ impl Workspace { &mut self, pane: ViewHandle, direction: SplitDirection, - ctx: &mut ViewContext, + cx: &mut ViewContext, ) -> ViewHandle { - let new_pane = self.add_pane(ctx); - self.activate_pane(new_pane.clone(), ctx); - if let Some(item) = pane.read(ctx).active_item() { - if let Some(clone) = item.clone_on_split(ctx.as_mut()) { - self.add_item_view(clone, ctx); + let new_pane = self.add_pane(cx); + self.activate_pane(new_pane.clone(), cx); + if let Some(item) = pane.read(cx).active_item() { + if let Some(clone) = item.clone_on_split(cx.as_mut()) { + self.add_item_view(clone, cx); } } self.center .split(pane.id(), new_pane.id(), direction) .unwrap(); - ctx.notify(); + cx.notify(); new_pane } - fn remove_pane(&mut self, pane: ViewHandle, ctx: &mut ViewContext) { + fn remove_pane(&mut self, pane: ViewHandle, cx: &mut ViewContext) { if self.center.remove(pane.id()).unwrap() { self.panes.retain(|p| p != &pane); - self.activate_pane(self.panes.last().unwrap().clone(), ctx); + self.activate_pane(self.panes.last().unwrap().clone(), cx); } } @@ -715,12 +715,12 @@ impl Workspace { &self.active_pane } - fn add_item_view(&self, item: Box, ctx: &mut ViewContext) { + fn add_item_view(&self, item: Box, cx: &mut ViewContext) { let active_pane = self.active_pane(); - item.set_parent_pane(&active_pane, ctx.as_mut()); - active_pane.update(ctx, |pane, ctx| { - let item_idx = pane.add_item(item, ctx); - pane.activate_item(item_idx, ctx); + item.set_parent_pane(&active_pane, cx.as_mut()); + active_pane.update(cx, |pane, cx| { + let item_idx = pane.add_item(item, cx); + pane.activate_item(item_idx, cx); }); } } @@ -746,25 +746,25 @@ impl View for Workspace { .named("workspace") } - fn on_focus(&mut self, ctx: &mut ViewContext) { - ctx.focus(&self.active_pane); + fn on_focus(&mut self, cx: &mut ViewContext) { + cx.focus(&self.active_pane); } } #[cfg(test)] pub trait WorkspaceHandle { - fn file_entries(&self, app: &AppContext) -> Vec<(usize, Arc)>; + fn file_entries(&self, cx: &AppContext) -> Vec<(usize, Arc)>; } #[cfg(test)] impl WorkspaceHandle for ViewHandle { - fn file_entries(&self, app: &AppContext) -> Vec<(usize, Arc)> { - self.read(app) + fn file_entries(&self, cx: &AppContext) -> Vec<(usize, Arc)> { + self.read(cx) .worktrees() .iter() .flat_map(|tree| { let tree_id = tree.id(); - tree.read(app) + tree.read(cx) .files(0) .map(move |f| (tree_id, f.path().clone())) }) @@ -784,10 +784,10 @@ mod tests { use tempdir::TempDir; #[gpui::test] - fn test_open_paths_action(app: &mut gpui::MutableAppContext) { - let app_state = build_app_state(app.as_ref()); + fn test_open_paths_action(cx: &mut gpui::MutableAppContext) { + let app_state = build_app_state(cx.as_ref()); - init(app); + init(cx); let dir = temp_tree(json!({ "a": { @@ -804,7 +804,7 @@ mod tests { }, })); - app.dispatch_global_action( + cx.dispatch_global_action( "workspace:open_paths", OpenParams { paths: vec![ @@ -814,22 +814,22 @@ mod tests { app_state: app_state.clone(), }, ); - assert_eq!(app.window_ids().count(), 1); + assert_eq!(cx.window_ids().count(), 1); - app.dispatch_global_action( + cx.dispatch_global_action( "workspace:open_paths", OpenParams { paths: vec![dir.path().join("a").to_path_buf()], app_state: app_state.clone(), }, ); - assert_eq!(app.window_ids().count(), 1); - let workspace_view_1 = app - .root_view::(app.window_ids().next().unwrap()) + assert_eq!(cx.window_ids().count(), 1); + let workspace_view_1 = cx + .root_view::(cx.window_ids().next().unwrap()) .unwrap(); - assert_eq!(workspace_view_1.read(app).worktrees().len(), 2); + assert_eq!(workspace_view_1.read(cx).worktrees().len(), 2); - app.dispatch_global_action( + cx.dispatch_global_action( "workspace:open_paths", OpenParams { paths: vec![ @@ -839,11 +839,11 @@ mod tests { app_state: app_state.clone(), }, ); - assert_eq!(app.window_ids().count(), 2); + assert_eq!(cx.window_ids().count(), 2); } #[gpui::test] - async fn test_open_entry(mut app: gpui::TestAppContext) { + async fn test_open_entry(mut cx: gpui::TestAppContext) { let dir = temp_tree(json!({ "a": { "file1": "contents 1", @@ -852,31 +852,31 @@ mod tests { }, })); - let app_state = app.read(build_app_state); + let app_state = cx.read(build_app_state); - let (_, workspace) = app.add_window(|ctx| { + let (_, workspace) = cx.add_window(|cx| { let mut workspace = - Workspace::new(0, app_state.settings, app_state.language_registry, ctx); - workspace.add_worktree(dir.path(), ctx); + Workspace::new(0, app_state.settings, app_state.language_registry, cx); + workspace.add_worktree(dir.path(), cx); workspace }); - app.read(|ctx| workspace.read(ctx).worktree_scans_complete(ctx)) + cx.read(|cx| workspace.read(cx).worktree_scans_complete(cx)) .await; - let entries = app.read(|ctx| workspace.file_entries(ctx)); + let entries = cx.read(|cx| workspace.file_entries(cx)); let file1 = entries[0].clone(); let file2 = entries[1].clone(); let file3 = entries[2].clone(); // Open the first entry workspace - .update(&mut app, |w, ctx| w.open_entry(file1.clone(), ctx)) + .update(&mut cx, |w, cx| w.open_entry(file1.clone(), cx)) .unwrap() .await; - app.read(|ctx| { - let pane = workspace.read(ctx).active_pane().read(ctx); + cx.read(|cx| { + let pane = workspace.read(cx).active_pane().read(cx); assert_eq!( - pane.active_item().unwrap().entry_id(ctx), + pane.active_item().unwrap().entry_id(cx), Some(file1.clone()) ); assert_eq!(pane.items().len(), 1); @@ -884,72 +884,72 @@ mod tests { // Open the second entry workspace - .update(&mut app, |w, ctx| w.open_entry(file2.clone(), ctx)) + .update(&mut cx, |w, cx| w.open_entry(file2.clone(), cx)) .unwrap() .await; - app.read(|ctx| { - let pane = workspace.read(ctx).active_pane().read(ctx); + cx.read(|cx| { + let pane = workspace.read(cx).active_pane().read(cx); assert_eq!( - pane.active_item().unwrap().entry_id(ctx), + pane.active_item().unwrap().entry_id(cx), Some(file2.clone()) ); assert_eq!(pane.items().len(), 2); }); // Open the first entry again. The existing pane item is activated. - workspace.update(&mut app, |w, ctx| { - assert!(w.open_entry(file1.clone(), ctx).is_none()) + workspace.update(&mut cx, |w, cx| { + assert!(w.open_entry(file1.clone(), cx).is_none()) }); - app.read(|ctx| { - let pane = workspace.read(ctx).active_pane().read(ctx); + cx.read(|cx| { + let pane = workspace.read(cx).active_pane().read(cx); assert_eq!( - pane.active_item().unwrap().entry_id(ctx), + pane.active_item().unwrap().entry_id(cx), Some(file1.clone()) ); assert_eq!(pane.items().len(), 2); }); // Split the pane with the first entry, then open the second entry again. - workspace.update(&mut app, |w, ctx| { - w.split_pane(w.active_pane().clone(), SplitDirection::Right, ctx); - assert!(w.open_entry(file2.clone(), ctx).is_none()); + workspace.update(&mut cx, |w, cx| { + w.split_pane(w.active_pane().clone(), SplitDirection::Right, cx); + assert!(w.open_entry(file2.clone(), cx).is_none()); assert_eq!( w.active_pane() - .read(ctx) + .read(cx) .active_item() .unwrap() - .entry_id(ctx.as_ref()), + .entry_id(cx.as_ref()), Some(file2.clone()) ); }); // Open the third entry twice concurrently. Two pane items // are added. - let (t1, t2) = workspace.update(&mut app, |w, ctx| { + let (t1, t2) = workspace.update(&mut cx, |w, cx| { ( - w.open_entry(file3.clone(), ctx).unwrap(), - w.open_entry(file3.clone(), ctx).unwrap(), + w.open_entry(file3.clone(), cx).unwrap(), + w.open_entry(file3.clone(), cx).unwrap(), ) }); t1.await; t2.await; - app.read(|ctx| { - let pane = workspace.read(ctx).active_pane().read(ctx); + cx.read(|cx| { + let pane = workspace.read(cx).active_pane().read(cx); assert_eq!( - pane.active_item().unwrap().entry_id(ctx), + pane.active_item().unwrap().entry_id(cx), Some(file3.clone()) ); let pane_entries = pane .items() .iter() - .map(|i| i.entry_id(ctx).unwrap()) + .map(|i| i.entry_id(cx).unwrap()) .collect::>(); assert_eq!(pane_entries, &[file1, file2, file3.clone(), file3]); }); } #[gpui::test] - async fn test_open_paths(mut app: gpui::TestAppContext) { + async fn test_open_paths(mut cx: gpui::TestAppContext) { let dir1 = temp_tree(json!({ "a.txt": "", })); @@ -957,49 +957,49 @@ mod tests { "b.txt": "", })); - let app_state = app.read(build_app_state); - let (_, workspace) = app.add_window(|ctx| { + let app_state = cx.read(build_app_state); + let (_, workspace) = cx.add_window(|cx| { let mut workspace = - Workspace::new(0, app_state.settings, app_state.language_registry, ctx); - workspace.add_worktree(dir1.path(), ctx); + Workspace::new(0, app_state.settings, app_state.language_registry, cx); + workspace.add_worktree(dir1.path(), cx); workspace }); - app.read(|ctx| workspace.read(ctx).worktree_scans_complete(ctx)) + cx.read(|cx| workspace.read(cx).worktree_scans_complete(cx)) .await; // Open a file within an existing worktree. - app.update(|ctx| { - workspace.update(ctx, |view, ctx| { - view.open_paths(&[dir1.path().join("a.txt")], ctx) + cx.update(|cx| { + workspace.update(cx, |view, cx| { + view.open_paths(&[dir1.path().join("a.txt")], cx) }) }) .await; - app.read(|ctx| { + cx.read(|cx| { assert_eq!( workspace - .read(ctx) + .read(cx) .active_pane() - .read(ctx) + .read(cx) .active_item() .unwrap() - .title(ctx), + .title(cx), "a.txt" ); }); // Open a file outside of any existing worktree. - app.update(|ctx| { - workspace.update(ctx, |view, ctx| { - view.open_paths(&[dir2.path().join("b.txt")], ctx) + cx.update(|cx| { + workspace.update(cx, |view, cx| { + view.open_paths(&[dir2.path().join("b.txt")], cx) }) }) .await; - app.read(|ctx| { + cx.read(|cx| { let worktree_roots = workspace - .read(ctx) + .read(cx) .worktrees() .iter() - .map(|w| w.read(ctx).abs_path()) + .map(|w| w.read(cx).abs_path()) .collect::>(); assert_eq!( worktree_roots, @@ -1009,163 +1009,159 @@ mod tests { ); assert_eq!( workspace - .read(ctx) + .read(cx) .active_pane() - .read(ctx) + .read(cx) .active_item() .unwrap() - .title(ctx), + .title(cx), "b.txt" ); }); } #[gpui::test] - async fn test_save_conflicting_item(mut app: gpui::TestAppContext) { + async fn test_save_conflicting_item(mut cx: gpui::TestAppContext) { let dir = temp_tree(json!({ "a.txt": "", })); - let app_state = app.read(build_app_state); - let (window_id, workspace) = app.add_window(|ctx| { + let app_state = cx.read(build_app_state); + let (window_id, workspace) = cx.add_window(|cx| { let mut workspace = - Workspace::new(0, app_state.settings, app_state.language_registry, ctx); - workspace.add_worktree(dir.path(), ctx); + Workspace::new(0, app_state.settings, app_state.language_registry, cx); + workspace.add_worktree(dir.path(), cx); workspace }); - let tree = app.read(|ctx| { - let mut trees = workspace.read(ctx).worktrees().iter(); + let tree = cx.read(|cx| { + let mut trees = workspace.read(cx).worktrees().iter(); trees.next().unwrap().clone() }); - tree.flush_fs_events(&app).await; + tree.flush_fs_events(&cx).await; // Open a file within an existing worktree. - app.update(|ctx| { - workspace.update(ctx, |view, ctx| { - view.open_paths(&[dir.path().join("a.txt")], ctx) + cx.update(|cx| { + workspace.update(cx, |view, cx| { + view.open_paths(&[dir.path().join("a.txt")], cx) }) }) .await; - let editor = app.read(|ctx| { - let pane = workspace.read(ctx).active_pane().read(ctx); + let editor = cx.read(|cx| { + let pane = workspace.read(cx).active_pane().read(cx); let item = pane.active_item().unwrap(); item.to_any().downcast::().unwrap() }); - app.update(|ctx| editor.update(ctx, |editor, ctx| editor.insert(&"x".to_string(), ctx))); + cx.update(|cx| editor.update(cx, |editor, cx| editor.insert(&"x".to_string(), cx))); fs::write(dir.path().join("a.txt"), "changed").unwrap(); editor - .condition(&app, |editor, ctx| editor.has_conflict(ctx)) + .condition(&cx, |editor, cx| editor.has_conflict(cx)) .await; - app.read(|ctx| assert!(editor.is_dirty(ctx))); + cx.read(|cx| assert!(editor.is_dirty(cx))); - app.update(|ctx| workspace.update(ctx, |w, ctx| w.save_active_item(&(), ctx))); - app.simulate_prompt_answer(window_id, 0); + cx.update(|cx| workspace.update(cx, |w, cx| w.save_active_item(&(), cx))); + cx.simulate_prompt_answer(window_id, 0); editor - .condition(&app, |editor, ctx| !editor.is_dirty(ctx)) + .condition(&cx, |editor, cx| !editor.is_dirty(cx)) .await; - app.read(|ctx| assert!(!editor.has_conflict(ctx))); + cx.read(|cx| assert!(!editor.has_conflict(cx))); } #[gpui::test] - async fn test_open_and_save_new_file(mut app: gpui::TestAppContext) { + async fn test_open_and_save_new_file(mut cx: gpui::TestAppContext) { let dir = TempDir::new("test-new-file").unwrap(); - let app_state = app.read(build_app_state); - let (_, workspace) = app.add_window(|ctx| { + let app_state = cx.read(build_app_state); + let (_, workspace) = cx.add_window(|cx| { let mut workspace = - Workspace::new(0, app_state.settings, app_state.language_registry, ctx); - workspace.add_worktree(dir.path(), ctx); + Workspace::new(0, app_state.settings, app_state.language_registry, cx); + workspace.add_worktree(dir.path(), cx); workspace }); - let tree = app.read(|ctx| { + let tree = cx.read(|cx| { workspace - .read(ctx) + .read(cx) .worktrees() .iter() .next() .unwrap() .clone() }); - tree.flush_fs_events(&app).await; + tree.flush_fs_events(&cx).await; // Create a new untitled buffer - let editor = workspace.update(&mut app, |workspace, ctx| { - workspace.open_new_file(&(), ctx); + let editor = workspace.update(&mut cx, |workspace, cx| { + workspace.open_new_file(&(), cx); workspace - .active_item(ctx) + .active_item(cx) .unwrap() .to_any() .downcast::() .unwrap() }); - editor.update(&mut app, |editor, ctx| { - assert!(!editor.is_dirty(ctx.as_ref())); - assert_eq!(editor.title(ctx.as_ref()), "untitled"); - editor.insert(&"hi".to_string(), ctx); - assert!(editor.is_dirty(ctx.as_ref())); + editor.update(&mut cx, |editor, cx| { + assert!(!editor.is_dirty(cx.as_ref())); + assert_eq!(editor.title(cx.as_ref()), "untitled"); + editor.insert(&"hi".to_string(), cx); + assert!(editor.is_dirty(cx.as_ref())); }); // Save the buffer. This prompts for a filename. - workspace.update(&mut app, |workspace, ctx| { - workspace.save_active_item(&(), ctx) - }); - app.simulate_new_path_selection(|parent_dir| { + workspace.update(&mut cx, |workspace, cx| workspace.save_active_item(&(), cx)); + cx.simulate_new_path_selection(|parent_dir| { assert_eq!(parent_dir, dir.path()); Some(parent_dir.join("the-new-name")) }); - app.read(|ctx| { - assert!(editor.is_dirty(ctx)); - assert_eq!(editor.title(ctx), "untitled"); + cx.read(|cx| { + assert!(editor.is_dirty(cx)); + assert_eq!(editor.title(cx), "untitled"); }); // When the save completes, the buffer's title is updated. editor - .condition(&app, |editor, ctx| !editor.is_dirty(ctx)) + .condition(&cx, |editor, cx| !editor.is_dirty(cx)) .await; - app.read(|ctx| { - assert!(!editor.is_dirty(ctx)); - assert_eq!(editor.title(ctx), "the-new-name"); + cx.read(|cx| { + assert!(!editor.is_dirty(cx)); + assert_eq!(editor.title(cx), "the-new-name"); }); // Edit the file and save it again. This time, there is no filename prompt. - editor.update(&mut app, |editor, ctx| { - editor.insert(&" there".to_string(), ctx); - assert_eq!(editor.is_dirty(ctx.as_ref()), true); + editor.update(&mut cx, |editor, cx| { + editor.insert(&" there".to_string(), cx); + assert_eq!(editor.is_dirty(cx.as_ref()), true); }); - workspace.update(&mut app, |workspace, ctx| { - workspace.save_active_item(&(), ctx) - }); - assert!(!app.did_prompt_for_new_path()); + workspace.update(&mut cx, |workspace, cx| workspace.save_active_item(&(), cx)); + assert!(!cx.did_prompt_for_new_path()); editor - .condition(&app, |editor, ctx| !editor.is_dirty(ctx)) + .condition(&cx, |editor, cx| !editor.is_dirty(cx)) .await; - app.read(|ctx| assert_eq!(editor.title(ctx), "the-new-name")); + cx.read(|cx| assert_eq!(editor.title(cx), "the-new-name")); // Open the same newly-created file in another pane item. The new editor should reuse // the same buffer. - workspace.update(&mut app, |workspace, ctx| { - workspace.open_new_file(&(), ctx); - workspace.split_pane(workspace.active_pane().clone(), SplitDirection::Right, ctx); + workspace.update(&mut cx, |workspace, cx| { + workspace.open_new_file(&(), cx); + workspace.split_pane(workspace.active_pane().clone(), SplitDirection::Right, cx); assert!(workspace - .open_entry((tree.id(), Path::new("the-new-name").into()), ctx) + .open_entry((tree.id(), Path::new("the-new-name").into()), cx) .is_none()); }); - let editor2 = workspace.update(&mut app, |workspace, ctx| { + let editor2 = workspace.update(&mut cx, |workspace, cx| { workspace - .active_item(ctx) + .active_item(cx) .unwrap() .to_any() .downcast::() .unwrap() }); - app.read(|ctx| { - assert_eq!(editor2.read(ctx).buffer(), editor.read(ctx).buffer()); + cx.read(|cx| { + assert_eq!(editor2.read(cx).buffer(), editor.read(cx).buffer()); }) } #[gpui::test] - async fn test_pane_actions(mut app: gpui::TestAppContext) { - app.update(|ctx| pane::init(ctx)); + async fn test_pane_actions(mut cx: gpui::TestAppContext) { + cx.update(|cx| pane::init(cx)); let dir = temp_tree(json!({ "a": { @@ -1175,41 +1171,41 @@ mod tests { }, })); - let app_state = app.read(build_app_state); - let (window_id, workspace) = app.add_window(|ctx| { + let app_state = cx.read(build_app_state); + let (window_id, workspace) = cx.add_window(|cx| { let mut workspace = - Workspace::new(0, app_state.settings, app_state.language_registry, ctx); - workspace.add_worktree(dir.path(), ctx); + Workspace::new(0, app_state.settings, app_state.language_registry, cx); + workspace.add_worktree(dir.path(), cx); workspace }); - app.read(|ctx| workspace.read(ctx).worktree_scans_complete(ctx)) + cx.read(|cx| workspace.read(cx).worktree_scans_complete(cx)) .await; - let entries = app.read(|ctx| workspace.file_entries(ctx)); + let entries = cx.read(|cx| workspace.file_entries(cx)); let file1 = entries[0].clone(); - let pane_1 = app.read(|ctx| workspace.read(ctx).active_pane().clone()); + let pane_1 = cx.read(|cx| workspace.read(cx).active_pane().clone()); workspace - .update(&mut app, |w, ctx| w.open_entry(file1.clone(), ctx)) + .update(&mut cx, |w, cx| w.open_entry(file1.clone(), cx)) .unwrap() .await; - app.read(|ctx| { + cx.read(|cx| { assert_eq!( - pane_1.read(ctx).active_item().unwrap().entry_id(ctx), + pane_1.read(cx).active_item().unwrap().entry_id(cx), Some(file1.clone()) ); }); - app.dispatch_action(window_id, vec![pane_1.id()], "pane:split_right", ()); - app.update(|ctx| { - let pane_2 = workspace.read(ctx).active_pane().clone(); + cx.dispatch_action(window_id, vec![pane_1.id()], "pane:split_right", ()); + cx.update(|cx| { + let pane_2 = workspace.read(cx).active_pane().clone(); assert_ne!(pane_1, pane_2); - let pane2_item = pane_2.read(ctx).active_item().unwrap(); - assert_eq!(pane2_item.entry_id(ctx.as_ref()), Some(file1.clone())); + let pane2_item = pane_2.read(cx).active_item().unwrap(); + assert_eq!(pane2_item.entry_id(cx.as_ref()), Some(file1.clone())); - ctx.dispatch_action(window_id, vec![pane_2.id()], "pane:close_active_item", ()); - let workspace_view = workspace.read(ctx); + cx.dispatch_action(window_id, vec![pane_2.id()], "pane:close_active_item", ()); + let workspace_view = workspace.read(cx); assert_eq!(workspace_view.panes.len(), 1); assert_eq!(workspace_view.active_pane(), &pane_1); });