Take WindowContext in workspace::ItemHandle methods

This commit is contained in:
Antonio Scandurra 2023-04-14 16:36:23 +02:00
parent a8e75a9b55
commit a820862165
5 changed files with 67 additions and 74 deletions

View file

@ -23,7 +23,7 @@ use util::{
test::{marked_text_ranges, marked_text_ranges_by, sample_text, TextRangeMarker}, test::{marked_text_ranges, marked_text_ranges_by, sample_text, TextRangeMarker},
}; };
use workspace::{ use workspace::{
item::{FollowableItem, ItemHandle}, item::{FollowableItem, Item, ItemHandle},
NavigationEntry, Pane, ViewId, NavigationEntry, Pane, ViewId,
}; };
@ -3973,7 +3973,7 @@ async fn test_document_format_during_save(cx: &mut gpui::TestAppContext) {
editor.update(cx, |editor, cx| editor.set_text("one\ntwo\nthree\n", cx)); editor.update(cx, |editor, cx| editor.set_text("one\ntwo\nthree\n", cx));
assert!(cx.read(|cx| editor.is_dirty(cx))); assert!(cx.read(|cx| editor.is_dirty(cx)));
let save = cx.update(|cx| editor.save(project.clone(), cx)); let save = editor.update(cx, |editor, cx| editor.save(project.clone(), cx));
fake_server fake_server
.handle_request::<lsp::request::Formatting, _, _>(move |params, _| async move { .handle_request::<lsp::request::Formatting, _, _>(move |params, _| async move {
assert_eq!( assert_eq!(
@ -4008,7 +4008,7 @@ async fn test_document_format_during_save(cx: &mut gpui::TestAppContext) {
futures::future::pending::<()>().await; futures::future::pending::<()>().await;
unreachable!() unreachable!()
}); });
let save = cx.update(|cx| editor.save(project.clone(), cx)); let save = editor.update(cx, |editor, cx| editor.save(project.clone(), cx));
cx.foreground().advance_clock(super::FORMAT_TIMEOUT); cx.foreground().advance_clock(super::FORMAT_TIMEOUT);
cx.foreground().start_waiting(); cx.foreground().start_waiting();
save.await.unwrap(); save.await.unwrap();
@ -4031,7 +4031,7 @@ async fn test_document_format_during_save(cx: &mut gpui::TestAppContext) {
}) })
}); });
let save = cx.update(|cx| editor.save(project.clone(), cx)); let save = editor.update(cx, |editor, cx| editor.save(project.clone(), cx));
fake_server fake_server
.handle_request::<lsp::request::Formatting, _, _>(move |params, _| async move { .handle_request::<lsp::request::Formatting, _, _>(move |params, _| async move {
assert_eq!( assert_eq!(
@ -4087,7 +4087,7 @@ async fn test_range_format_during_save(cx: &mut gpui::TestAppContext) {
editor.update(cx, |editor, cx| editor.set_text("one\ntwo\nthree\n", cx)); editor.update(cx, |editor, cx| editor.set_text("one\ntwo\nthree\n", cx));
assert!(cx.read(|cx| editor.is_dirty(cx))); assert!(cx.read(|cx| editor.is_dirty(cx)));
let save = cx.update(|cx| editor.save(project.clone(), cx)); let save = editor.update(cx, |editor, cx| editor.save(project.clone(), cx));
fake_server fake_server
.handle_request::<lsp::request::RangeFormatting, _, _>(move |params, _| async move { .handle_request::<lsp::request::RangeFormatting, _, _>(move |params, _| async move {
assert_eq!( assert_eq!(
@ -4124,7 +4124,7 @@ async fn test_range_format_during_save(cx: &mut gpui::TestAppContext) {
unreachable!() unreachable!()
}, },
); );
let save = cx.update(|cx| editor.save(project.clone(), cx)); let save = editor.update(cx, |editor, cx| editor.save(project.clone(), cx));
cx.foreground().advance_clock(super::FORMAT_TIMEOUT); cx.foreground().advance_clock(super::FORMAT_TIMEOUT);
cx.foreground().start_waiting(); cx.foreground().start_waiting();
save.await.unwrap(); save.await.unwrap();
@ -4147,7 +4147,7 @@ async fn test_range_format_during_save(cx: &mut gpui::TestAppContext) {
}) })
}); });
let save = cx.update(|cx| editor.save(project.clone(), cx)); let save = editor.update(cx, |editor, cx| editor.save(project.clone(), cx));
fake_server fake_server
.handle_request::<lsp::request::RangeFormatting, _, _>(move |params, _| async move { .handle_request::<lsp::request::RangeFormatting, _, _>(move |params, _| async move {
assert_eq!( assert_eq!(

View file

@ -352,7 +352,7 @@ impl AsyncAppContext {
self.0.borrow_mut().update(callback) self.0.borrow_mut().update(callback)
} }
fn update_window<T, F: FnOnce(&mut WindowContext) -> T>( pub fn update_window<T, F: FnOnce(&mut WindowContext) -> T>(
&mut self, &mut self,
window_id: usize, window_id: usize,
callback: F, callback: F,

View file

@ -17,7 +17,7 @@ use anyhow::Result;
use client::{proto, Client}; use client::{proto, Client};
use gpui::{ use gpui::{
fonts::HighlightStyle, AnyViewHandle, AppContext, Element, ModelHandle, Task, View, fonts::HighlightStyle, AnyViewHandle, AppContext, Element, ModelHandle, Task, View,
ViewContext, ViewHandle, WeakViewHandle, ViewContext, ViewHandle, WeakViewHandle, WindowContext,
}; };
use project::{Project, ProjectEntryId, ProjectPath}; use project::{Project, ProjectEntryId, ProjectPath};
use settings::{Autosave, Settings}; use settings::{Autosave, Settings};
@ -170,7 +170,7 @@ pub trait Item: View {
pub trait ItemHandle: 'static + fmt::Debug { pub trait ItemHandle: 'static + fmt::Debug {
fn subscribe_to_item_events( fn subscribe_to_item_events(
&self, &self,
cx: &mut AppContext, cx: &mut WindowContext,
handler: Box<dyn Fn(ItemEvent, &mut AppContext)>, handler: Box<dyn Fn(ItemEvent, &mut AppContext)>,
) -> gpui::Subscription; ) -> gpui::Subscription;
fn tab_description<'a>(&self, detail: usize, cx: &'a AppContext) -> Option<Cow<'a, str>>; fn tab_description<'a>(&self, detail: usize, cx: &'a AppContext) -> Option<Cow<'a, str>>;
@ -189,7 +189,7 @@ pub trait ItemHandle: 'static + fmt::Debug {
fn clone_on_split( fn clone_on_split(
&self, &self,
workspace_id: WorkspaceId, workspace_id: WorkspaceId,
cx: &mut AppContext, cx: &mut WindowContext,
) -> Option<Box<dyn ItemHandle>>; ) -> Option<Box<dyn ItemHandle>>;
fn added_to_pane( fn added_to_pane(
&self, &self,
@ -197,27 +197,27 @@ pub trait ItemHandle: 'static + fmt::Debug {
pane: ViewHandle<Pane>, pane: ViewHandle<Pane>,
cx: &mut ViewContext<Workspace>, cx: &mut ViewContext<Workspace>,
); );
fn deactivated(&self, cx: &mut AppContext); fn deactivated(&self, cx: &mut WindowContext);
fn workspace_deactivated(&self, cx: &mut AppContext); fn workspace_deactivated(&self, cx: &mut WindowContext);
fn navigate(&self, data: Box<dyn Any>, cx: &mut AppContext) -> bool; fn navigate(&self, data: Box<dyn Any>, cx: &mut WindowContext) -> bool;
fn id(&self) -> usize; fn id(&self) -> usize;
fn window_id(&self) -> usize; fn window_id(&self) -> usize;
fn as_any(&self) -> &AnyViewHandle; fn as_any(&self) -> &AnyViewHandle;
fn is_dirty(&self, cx: &AppContext) -> bool; fn is_dirty(&self, cx: &AppContext) -> bool;
fn has_conflict(&self, cx: &AppContext) -> bool; fn has_conflict(&self, cx: &AppContext) -> bool;
fn can_save(&self, cx: &AppContext) -> bool; fn can_save(&self, cx: &AppContext) -> bool;
fn save(&self, project: ModelHandle<Project>, cx: &mut AppContext) -> Task<Result<()>>; fn save(&self, project: ModelHandle<Project>, cx: &mut WindowContext) -> Task<Result<()>>;
fn save_as( fn save_as(
&self, &self,
project: ModelHandle<Project>, project: ModelHandle<Project>,
abs_path: PathBuf, abs_path: PathBuf,
cx: &mut AppContext, cx: &mut WindowContext,
) -> Task<Result<()>>; ) -> Task<Result<()>>;
fn reload(&self, project: ModelHandle<Project>, cx: &mut AppContext) -> Task<Result<()>>; fn reload(&self, project: ModelHandle<Project>, cx: &mut WindowContext) -> Task<Result<()>>;
fn git_diff_recalc( fn git_diff_recalc(
&self, &self,
project: ModelHandle<Project>, project: ModelHandle<Project>,
cx: &mut AppContext, cx: &mut WindowContext,
) -> Task<Result<()>>; ) -> Task<Result<()>>;
fn act_as_type<'a>(&'a self, type_id: TypeId, cx: &'a AppContext) -> Option<&'a AnyViewHandle>; fn act_as_type<'a>(&'a self, type_id: TypeId, cx: &'a AppContext) -> Option<&'a AnyViewHandle>;
fn to_followable_item_handle(&self, cx: &AppContext) -> Option<Box<dyn FollowableItemHandle>>; fn to_followable_item_handle(&self, cx: &AppContext) -> Option<Box<dyn FollowableItemHandle>>;
@ -253,7 +253,7 @@ impl dyn ItemHandle {
impl<T: Item> ItemHandle for ViewHandle<T> { impl<T: Item> ItemHandle for ViewHandle<T> {
fn subscribe_to_item_events( fn subscribe_to_item_events(
&self, &self,
cx: &mut AppContext, cx: &mut WindowContext,
handler: Box<dyn Fn(ItemEvent, &mut AppContext)>, handler: Box<dyn Fn(ItemEvent, &mut AppContext)>,
) -> gpui::Subscription { ) -> gpui::Subscription {
cx.subscribe(self, move |_, event, cx| { cx.subscribe(self, move |_, event, cx| {
@ -320,7 +320,7 @@ impl<T: Item> ItemHandle for ViewHandle<T> {
fn clone_on_split( fn clone_on_split(
&self, &self,
workspace_id: WorkspaceId, workspace_id: WorkspaceId,
cx: &mut AppContext, cx: &mut WindowContext,
) -> Option<Box<dyn ItemHandle>> { ) -> Option<Box<dyn ItemHandle>> {
self.update(cx, |item, cx| { self.update(cx, |item, cx| {
cx.add_option_view(|cx| item.clone_on_split(workspace_id, cx)) cx.add_option_view(|cx| item.clone_on_split(workspace_id, cx))
@ -435,16 +435,9 @@ impl<T: Item> ItemHandle for ViewHandle<T> {
{ {
let delay = Duration::from_millis(milliseconds); let delay = Duration::from_millis(milliseconds);
let item = item.clone(); let item = item.clone();
pending_autosave.fire_new( pending_autosave.fire_new(delay, cx, move |workspace, cx| {
delay, Pane::autosave_item(&item, workspace.project().clone(), cx)
workspace, });
cx,
|project, mut cx| async move {
cx.update(|cx| Pane::autosave_item(&item, project, cx))
.await
.log_err();
},
);
} }
let settings = cx.global::<Settings>(); let settings = cx.global::<Settings>();
@ -460,22 +453,24 @@ impl<T: Item> ItemHandle for ViewHandle<T> {
pending_git_update.fire_new( pending_git_update.fire_new(
duration, duration,
workspace,
cx, cx,
|project, mut cx| async move { move |workspace, cx| {
cx.update(|cx| item.git_diff_recalc(project, cx)) item.git_diff_recalc(workspace.project().clone(), cx)
.await
.log_err();
}, },
); );
} else { } else {
let project = workspace.project().downgrade(); cx.spawn_weak(|workspace, mut cx| async move {
cx.spawn_weak(|_, mut cx| async move { workspace
if let Some(project) = project.upgrade(&cx) { .upgrade(&cx)?
cx.update(|cx| item.git_diff_recalc(project, cx)) .update(&mut cx, |workspace, cx| {
.await item.git_diff_recalc(
.log_err(); workspace.project().clone(),
} cx,
)
})
.await
.log_err()?;
Some(())
}) })
.detach(); .detach();
} }
@ -507,15 +502,15 @@ impl<T: Item> ItemHandle for ViewHandle<T> {
}); });
} }
fn deactivated(&self, cx: &mut AppContext) { fn deactivated(&self, cx: &mut WindowContext) {
self.update(cx, |this, cx| this.deactivated(cx)); self.update(cx, |this, cx| this.deactivated(cx));
} }
fn workspace_deactivated(&self, cx: &mut AppContext) { fn workspace_deactivated(&self, cx: &mut WindowContext) {
self.update(cx, |this, cx| this.workspace_deactivated(cx)); self.update(cx, |this, cx| this.workspace_deactivated(cx));
} }
fn navigate(&self, data: Box<dyn Any>, cx: &mut AppContext) -> bool { fn navigate(&self, data: Box<dyn Any>, cx: &mut WindowContext) -> bool {
self.update(cx, |this, cx| this.navigate(data, cx)) self.update(cx, |this, cx| this.navigate(data, cx))
} }
@ -543,7 +538,7 @@ impl<T: Item> ItemHandle for ViewHandle<T> {
self.read(cx).can_save(cx) self.read(cx).can_save(cx)
} }
fn save(&self, project: ModelHandle<Project>, cx: &mut AppContext) -> Task<Result<()>> { fn save(&self, project: ModelHandle<Project>, cx: &mut WindowContext) -> Task<Result<()>> {
self.update(cx, |item, cx| item.save(project, cx)) self.update(cx, |item, cx| item.save(project, cx))
} }
@ -551,19 +546,19 @@ impl<T: Item> ItemHandle for ViewHandle<T> {
&self, &self,
project: ModelHandle<Project>, project: ModelHandle<Project>,
abs_path: PathBuf, abs_path: PathBuf,
cx: &mut AppContext, cx: &mut WindowContext,
) -> Task<anyhow::Result<()>> { ) -> Task<anyhow::Result<()>> {
self.update(cx, |item, cx| item.save_as(project, abs_path, cx)) self.update(cx, |item, cx| item.save_as(project, abs_path, cx))
} }
fn reload(&self, project: ModelHandle<Project>, cx: &mut AppContext) -> Task<Result<()>> { fn reload(&self, project: ModelHandle<Project>, cx: &mut WindowContext) -> Task<Result<()>> {
self.update(cx, |item, cx| item.reload(project, cx)) self.update(cx, |item, cx| item.reload(project, cx))
} }
fn git_diff_recalc( fn git_diff_recalc(
&self, &self,
project: ModelHandle<Project>, project: ModelHandle<Project>,
cx: &mut AppContext, cx: &mut WindowContext,
) -> Task<Result<()>> { ) -> Task<Result<()>> {
self.update(cx, |item, cx| item.git_diff_recalc(project, cx)) self.update(cx, |item, cx| item.git_diff_recalc(project, cx))
} }

View file

@ -24,7 +24,7 @@ use gpui::{
keymap_matcher::KeymapContext, keymap_matcher::KeymapContext,
platform::{CursorStyle, MouseButton, NavigationDirection, PromptLevel}, platform::{CursorStyle, MouseButton, NavigationDirection, PromptLevel},
Action, AnyViewHandle, AnyWeakViewHandle, AppContext, AsyncAppContext, Entity, ModelHandle, Action, AnyViewHandle, AnyWeakViewHandle, AppContext, AsyncAppContext, Entity, ModelHandle,
MouseRegion, Quad, Task, View, ViewContext, ViewHandle, WeakViewHandle, MouseRegion, Quad, Task, View, ViewContext, ViewHandle, WeakViewHandle, WindowContext,
}; };
use project::{Project, ProjectEntryId, ProjectPath}; use project::{Project, ProjectEntryId, ProjectPath};
use serde::Deserialize; use serde::Deserialize;
@ -1106,8 +1106,8 @@ impl Pane {
) )
}); });
match answer.next().await { match answer.next().await {
Some(0) => cx.update(|cx| item.save(project, cx)).await?, Some(0) => pane.update(cx, |_, cx| item.save(project, cx)).await?,
Some(1) => cx.update(|cx| item.reload(project, cx)).await?, Some(1) => pane.update(cx, |_, cx| item.reload(project, cx)).await?,
_ => return Ok(false), _ => return Ok(false),
} }
} else if is_dirty && (can_save || is_singleton) { } else if is_dirty && (can_save || is_singleton) {
@ -1137,7 +1137,7 @@ impl Pane {
if should_save { if should_save {
if can_save { if can_save {
cx.update(|cx| item.save(project, cx)).await?; pane.update(cx, |_, cx| item.save(project, cx)).await?;
} else if is_singleton { } else if is_singleton {
let start_abs_path = project let start_abs_path = project
.read_with(cx, |project, cx| { .read_with(cx, |project, cx| {
@ -1148,7 +1148,8 @@ impl Pane {
let mut abs_path = cx.update(|cx| cx.prompt_for_new_path(&start_abs_path)); let mut abs_path = cx.update(|cx| cx.prompt_for_new_path(&start_abs_path));
if let Some(abs_path) = abs_path.next().await.flatten() { if let Some(abs_path) = abs_path.next().await.flatten() {
cx.update(|cx| item.save_as(project, abs_path, cx)).await?; pane.update(cx, |_, cx| item.save_as(project, abs_path, cx))
.await?;
} else { } else {
return Ok(false); return Ok(false);
} }
@ -1166,7 +1167,7 @@ impl Pane {
pub fn autosave_item( pub fn autosave_item(
item: &dyn ItemHandle, item: &dyn ItemHandle,
project: ModelHandle<Project>, project: ModelHandle<Project>,
cx: &mut AppContext, cx: &mut WindowContext,
) -> Task<Result<()>> { ) -> Task<Result<()>> {
if Self::can_autosave_item(item, cx) { if Self::can_autosave_item(item, cx) {
item.save(project, cx) item.save(project, cx)

View file

@ -561,27 +561,19 @@ impl DelayedDebouncedEditAction {
} }
} }
fn fire_new<F, Fut>( fn fire_new<F>(&mut self, delay: Duration, cx: &mut ViewContext<Workspace>, f: F)
&mut self, where
delay: Duration, F: 'static + FnOnce(&mut Workspace, &mut ViewContext<Workspace>) -> Task<Result<()>>,
workspace: &Workspace,
cx: &mut ViewContext<Workspace>,
f: F,
) where
F: FnOnce(ModelHandle<Project>, AsyncAppContext) -> Fut + 'static,
Fut: 'static + Future<Output = ()>,
{ {
if let Some(channel) = self.cancel_channel.take() { if let Some(channel) = self.cancel_channel.take() {
_ = channel.send(()); _ = channel.send(());
} }
let project = workspace.project().downgrade();
let (sender, mut receiver) = oneshot::channel::<()>(); let (sender, mut receiver) = oneshot::channel::<()>();
self.cancel_channel = Some(sender); self.cancel_channel = Some(sender);
let previous_task = self.task.take(); let previous_task = self.task.take();
self.task = Some(cx.spawn_weak(|_, cx| async move { self.task = Some(cx.spawn_weak(|workspace, mut cx| async move {
let mut timer = cx.background().timer(delay).fuse(); let mut timer = cx.background().timer(delay).fuse();
if let Some(previous_task) = previous_task { if let Some(previous_task) = previous_task {
previous_task.await; previous_task.await;
@ -592,8 +584,11 @@ impl DelayedDebouncedEditAction {
_ = timer => {} _ = timer => {}
} }
if let Some(project) = project.upgrade(&cx) { if let Some(workspace) = workspace.upgrade(&cx) {
(f)(project, cx).await; workspace
.update(&mut cx, |workspace, cx| (f)(workspace, cx))
.await
.log_err();
} }
})); }));
} }
@ -1412,15 +1407,16 @@ impl Workspace {
CONFLICT_MESSAGE, CONFLICT_MESSAGE,
&["Overwrite", "Cancel"], &["Overwrite", "Cancel"],
); );
cx.spawn(|_, mut cx| async move { cx.spawn(|this, mut cx| async move {
let answer = answer.recv().await; let answer = answer.recv().await;
if answer == Some(0) { if answer == Some(0) {
cx.update(|cx| item.save(project, cx)).await?; this.update(&mut cx, |this, cx| item.save(this.project.clone(), cx))
.await?;
} }
Ok(()) Ok(())
}) })
} else { } else {
item.save(project, cx) item.save(self.project.clone(), cx)
} }
} else if item.is_singleton(cx) { } else if item.is_singleton(cx) {
let worktree = self.worktrees(cx).next(); let worktree = self.worktrees(cx).next();
@ -1429,9 +1425,10 @@ impl Workspace {
.map_or(Path::new(""), |w| w.abs_path()) .map_or(Path::new(""), |w| w.abs_path())
.to_path_buf(); .to_path_buf();
let mut abs_path = cx.prompt_for_new_path(&start_abs_path); let mut abs_path = cx.prompt_for_new_path(&start_abs_path);
cx.spawn(|_, mut cx| async move { cx.spawn(|this, mut cx| async move {
if let Some(abs_path) = abs_path.recv().await.flatten() { if let Some(abs_path) = abs_path.recv().await.flatten() {
cx.update(|cx| item.save_as(project, abs_path, cx)).await?; this.update(&mut cx, |_, cx| item.save_as(project, abs_path, cx))
.await?;
} }
Ok(()) Ok(())
}) })