Finish up decoupling workspace from call

This commit is contained in:
Piotr Osiewicz 2023-11-21 20:51:53 +01:00
parent ebccdb64bc
commit abe5a9c85f
5 changed files with 126 additions and 153 deletions

1
Cargo.lock generated
View file

@ -1175,6 +1175,7 @@ version = "0.1.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"async-broadcast", "async-broadcast",
"async-trait",
"audio2", "audio2",
"client2", "client2",
"collections", "collections",

View file

@ -32,6 +32,7 @@ project = { package = "project2", path = "../project2" }
settings = { package = "settings2", path = "../settings2" } settings = { package = "settings2", path = "../settings2" }
util = { path = "../util" } util = { path = "../util" }
workspace = {package = "workspace2", path = "../workspace2"} workspace = {package = "workspace2", path = "../workspace2"}
async-trait.workspace = true
anyhow.workspace = true anyhow.workspace = true
async-broadcast = "0.4" async-broadcast = "0.4"
futures.workspace = true futures.workspace = true

View file

@ -2,24 +2,29 @@ pub mod call_settings;
pub mod participant; pub mod participant;
pub mod room; pub mod room;
use anyhow::{anyhow, Result}; use anyhow::{anyhow, bail, Result};
use async_trait::async_trait;
use audio::Audio; use audio::Audio;
use call_settings::CallSettings; use call_settings::CallSettings;
use client::{proto, Client, TelemetrySettings, TypedEnvelope, User, UserStore, ZED_ALWAYS_ACTIVE}; use client::{
proto::{self, PeerId},
Client, TelemetrySettings, TypedEnvelope, User, UserStore, ZED_ALWAYS_ACTIVE,
};
use collections::HashSet; use collections::HashSet;
use futures::{channel::oneshot, future::Shared, Future, FutureExt}; use futures::{channel::oneshot, future::Shared, Future, FutureExt};
use gpui::{ use gpui::{
AppContext, AsyncAppContext, Context, EventEmitter, Model, ModelContext, Subscription, Task, AppContext, AsyncAppContext, AsyncWindowContext, Context, EventEmitter, Model, ModelContext,
WeakModel, Subscription, Task, View, ViewContext, WeakModel, WeakView,
}; };
pub use participant::ParticipantLocation;
use postage::watch; use postage::watch;
use project::Project; use project::Project;
use room::Event; use room::Event;
pub use room::Room;
use settings::Settings; use settings::Settings;
use std::sync::Arc; use std::sync::Arc;
use util::ResultExt;
pub use participant::ParticipantLocation; use workspace::{item::ItemHandle, CallHandler, Pane, Workspace};
pub use room::Room;
pub fn init(client: Arc<Client>, user_store: Model<UserStore>, cx: &mut AppContext) { pub fn init(client: Arc<Client>, user_store: Model<UserStore>, cx: &mut AppContext) {
CallSettings::register(cx); CallSettings::register(cx);
@ -505,35 +510,36 @@ pub fn report_call_event_for_channel(
) )
} }
struct Call { pub struct Call {
follower_states: HashMap<View<Pane>, FollowerState>,
active_call: Option<(Model<ActiveCall>, Vec<Subscription>)>, active_call: Option<(Model<ActiveCall>, Vec<Subscription>)>,
parent_workspace: WeakView<Workspace>, parent_workspace: WeakView<Workspace>,
} }
impl Call { impl Call {
fn new(parent_workspace: WeakView<Workspace>, cx: &mut ViewContext<'_, Workspace>) -> Self { pub fn new(
parent_workspace: WeakView<Workspace>,
cx: &mut ViewContext<'_, Workspace>,
) -> Box<dyn CallHandler> {
let mut active_call = None; let mut active_call = None;
if cx.has_global::<Model<ActiveCall>>() { if cx.has_global::<Model<ActiveCall>>() {
let call = cx.global::<Model<ActiveCall>>().clone(); let call = cx.global::<Model<ActiveCall>>().clone();
let subscriptions = vec![cx.subscribe(&call, Self::on_active_call_event)]; let subscriptions = vec![cx.subscribe(&call, Self::on_active_call_event)];
active_call = Some((call, subscriptions)); active_call = Some((call, subscriptions));
} }
Self { Box::new(Self {
follower_states: Default::default(),
active_call, active_call,
parent_workspace, parent_workspace,
} })
} }
fn on_active_call_event( fn on_active_call_event(
workspace: &mut Workspace, workspace: &mut Workspace,
_: Model<ActiveCall>, _: Model<ActiveCall>,
event: &call2::room::Event, event: &room::Event,
cx: &mut ViewContext<Workspace>, cx: &mut ViewContext<Workspace>,
) { ) {
match event { match event {
call2::room::Event::ParticipantLocationChanged { participant_id } room::Event::ParticipantLocationChanged { participant_id }
| call2::room::Event::RemoteVideoTracksChanged { participant_id } => { | room::Event::RemoteVideoTracksChanged { participant_id } => {
workspace.leader_updated(*participant_id, cx); workspace.leader_updated(*participant_id, cx);
} }
_ => {} _ => {}
@ -543,78 +549,6 @@ impl Call {
#[async_trait(?Send)] #[async_trait(?Send)]
impl CallHandler for Call { impl CallHandler for Call {
fn leader_updated(&mut self, leader_id: PeerId, cx: &mut ViewContext<Workspace>) -> Option<()> {
cx.notify();
let (call, _) = self.active_call.as_ref()?;
let room = call.read(cx).room()?.read(cx);
let participant = room.remote_participant_for_peer_id(leader_id)?;
let mut items_to_activate = Vec::new();
let leader_in_this_app;
let leader_in_this_project;
match participant.location {
call2::ParticipantLocation::SharedProject { project_id } => {
leader_in_this_app = true;
leader_in_this_project = Some(project_id)
== self
.parent_workspace
.update(cx, |this, cx| this.project.read(cx).remote_id())
.log_err()
.flatten();
}
call2::ParticipantLocation::UnsharedProject => {
leader_in_this_app = true;
leader_in_this_project = false;
}
call2::ParticipantLocation::External => {
leader_in_this_app = false;
leader_in_this_project = false;
}
};
for (pane, state) in &self.follower_states {
if state.leader_id != leader_id {
continue;
}
if let (Some(active_view_id), true) = (state.active_view_id, leader_in_this_app) {
if let Some(item) = state.items_by_leader_view_id.get(&active_view_id) {
if leader_in_this_project || !item.is_project_item(cx) {
items_to_activate.push((pane.clone(), item.boxed_clone()));
}
} else {
log::warn!(
"unknown view id {:?} for leader {:?}",
active_view_id,
leader_id
);
}
continue;
}
// todo!()
// if let Some(shared_screen) = self.shared_screen_for_peer(leader_id, pane, cx) {
// items_to_activate.push((pane.clone(), Box::new(shared_screen)));
// }
}
for (pane, item) in items_to_activate {
let pane_was_focused = pane.read(cx).has_focus(cx);
if let Some(index) = pane.update(cx, |pane, _| pane.index_for_item(item.as_ref())) {
pane.update(cx, |pane, cx| pane.activate_item(index, false, false, cx));
} else {
pane.update(cx, |pane, mut cx| {
pane.add_item(item.boxed_clone(), false, false, None, &mut cx)
});
}
if pane_was_focused {
pane.update(cx, |pane, cx| pane.focus_active_item(cx));
}
}
None
}
fn shared_screen_for_peer( fn shared_screen_for_peer(
&self, &self,
peer_id: PeerId, peer_id: PeerId,
@ -638,12 +572,6 @@ impl CallHandler for Call {
// }))) // })))
} }
fn follower_states_mut(&mut self) -> &mut HashMap<View<Pane>, FollowerState> {
&mut self.follower_states
}
fn follower_states(&self) -> &HashMap<View<Pane>, FollowerState> {
&self.follower_states
}
fn room_id(&self, cx: &AppContext) -> Option<u64> { fn room_id(&self, cx: &AppContext) -> Option<u64> {
Some(self.active_call.as_ref()?.0.read(cx).room()?.read(cx).id()) Some(self.active_call.as_ref()?.0.read(cx).room()?.read(cx).id())
} }
@ -657,6 +585,39 @@ impl CallHandler for Call {
fn active_project(&self, cx: &AppContext) -> Option<WeakModel<Project>> { fn active_project(&self, cx: &AppContext) -> Option<WeakModel<Project>> {
ActiveCall::global(cx).read(cx).location().cloned() ActiveCall::global(cx).read(cx).location().cloned()
} }
fn peer_state(
&mut self,
leader_id: PeerId,
cx: &mut ViewContext<Workspace>,
) -> Option<(bool, bool)> {
let (call, _) = self.active_call.as_ref()?;
let room = call.read(cx).room()?.read(cx);
let participant = room.remote_participant_for_peer_id(leader_id)?;
let leader_in_this_app;
let leader_in_this_project;
match participant.location {
ParticipantLocation::SharedProject { project_id } => {
leader_in_this_app = true;
leader_in_this_project = Some(project_id)
== self
.parent_workspace
.update(cx, |this, cx| this.project().read(cx).remote_id())
.log_err()
.flatten();
}
ParticipantLocation::UnsharedProject => {
leader_in_this_app = true;
leader_in_this_project = false;
}
ParticipantLocation::External => {
leader_in_this_app = false;
leader_in_this_project = false;
}
};
Some((leader_in_this_project, leader_in_this_app))
}
} }
#[cfg(test)] #[cfg(test)]

View file

@ -15,7 +15,7 @@ mod status_bar;
mod toolbar; mod toolbar;
mod workspace_settings; mod workspace_settings;
use anyhow::{anyhow, bail, Context as _, Result}; use anyhow::{anyhow, Context as _, Result};
use async_trait::async_trait; use async_trait::async_trait;
use client2::{ use client2::{
proto::{self, PeerId}, proto::{self, PeerId},
@ -207,10 +207,10 @@ pub fn init_settings(cx: &mut AppContext) {
ItemSettings::register(cx); ItemSettings::register(cx);
} }
pub fn init(app_state: Arc<AppState>, cx: &mut AppContext) { pub fn init(app_state: Arc<AppState>, cx: &mut AppContext, call_factory: CallFactory) {
init_settings(cx); init_settings(cx);
notifications::init(cx); notifications::init(cx);
cx.set_global(call_factory);
// cx.add_global_action({ // cx.add_global_action({
// let app_state = Arc::downgrade(&app_state); // let app_state = Arc::downgrade(&app_state);
// move |_: &Open, cx: &mut AppContext| { // move |_: &Open, cx: &mut AppContext| {
@ -410,15 +410,13 @@ pub enum Event {
#[async_trait(?Send)] #[async_trait(?Send)]
pub trait CallHandler { pub trait CallHandler {
fn leader_updated(&mut self, leader_id: PeerId, cx: &mut ViewContext<Workspace>) -> Option<()>; fn peer_state(&mut self, id: PeerId, cx: &mut ViewContext<Workspace>) -> Option<(bool, bool)>;
fn shared_screen_for_peer( fn shared_screen_for_peer(
&self, &self,
peer_id: PeerId, peer_id: PeerId,
pane: &View<Pane>, pane: &View<Pane>,
cx: &mut ViewContext<Workspace>, cx: &mut ViewContext<Workspace>,
) -> Option<Box<dyn ItemHandle>>; ) -> Option<Box<dyn ItemHandle>>;
fn follower_states_mut(&mut self) -> &mut HashMap<View<Pane>, FollowerState>;
fn follower_states(&self) -> &HashMap<View<Pane>, FollowerState>;
fn room_id(&self, cx: &AppContext) -> Option<u64>; fn room_id(&self, cx: &AppContext) -> Option<u64>;
fn is_in_room(&self, cx: &mut ViewContext<Workspace>) -> bool { fn is_in_room(&self, cx: &mut ViewContext<Workspace>) -> bool {
self.room_id(cx).is_some() self.room_id(cx).is_some()
@ -448,6 +446,7 @@ pub struct Workspace {
notifications: Vec<(TypeId, usize, Box<dyn NotificationHandle>)>, notifications: Vec<(TypeId, usize, Box<dyn NotificationHandle>)>,
project: Model<Project>, project: Model<Project>,
call_handler: Box<dyn CallHandler>, call_handler: Box<dyn CallHandler>,
follower_states: HashMap<View<Pane>, FollowerState>,
last_leaders_by_pane: HashMap<WeakView<Pane>, PeerId>, last_leaders_by_pane: HashMap<WeakView<Pane>, PeerId>,
window_edited: bool, window_edited: bool,
leader_updates_tx: mpsc::UnboundedSender<(PeerId, proto::UpdateFollowers)>, leader_updates_tx: mpsc::UnboundedSender<(PeerId, proto::UpdateFollowers)>,
@ -458,7 +457,6 @@ pub struct Workspace {
_observe_current_user: Task<Result<()>>, _observe_current_user: Task<Result<()>>,
_schedule_serialize: Option<Task<()>>, _schedule_serialize: Option<Task<()>>,
pane_history_timestamp: Arc<AtomicUsize>, pane_history_timestamp: Arc<AtomicUsize>,
call_factory: CallFactory,
} }
impl EventEmitter<Event> for Workspace {} impl EventEmitter<Event> for Workspace {}
@ -484,7 +482,6 @@ impl Workspace {
workspace_id: WorkspaceId, workspace_id: WorkspaceId,
project: Model<Project>, project: Model<Project>,
app_state: Arc<AppState>, app_state: Arc<AppState>,
call_factory: CallFactory,
cx: &mut ViewContext<Self>, cx: &mut ViewContext<Self>,
) -> Self { ) -> Self {
cx.observe(&project, |_, _, cx| cx.notify()).detach(); cx.observe(&project, |_, _, cx| cx.notify()).detach();
@ -656,6 +653,7 @@ impl Workspace {
]; ];
cx.defer(|this, cx| this.update_window_title(cx)); cx.defer(|this, cx| this.update_window_title(cx));
let call_factory = cx.global::<CallFactory>();
Workspace { Workspace {
window_self: window_handle, window_self: window_handle,
weak_self: weak_handle.clone(), weak_self: weak_handle.clone(),
@ -675,7 +673,7 @@ impl Workspace {
bottom_dock, bottom_dock,
right_dock, right_dock,
project: project.clone(), project: project.clone(),
follower_states: Default::default(),
last_leaders_by_pane: Default::default(), last_leaders_by_pane: Default::default(),
window_edited: false, window_edited: false,
@ -689,7 +687,6 @@ impl Workspace {
subscriptions, subscriptions,
pane_history_timestamp, pane_history_timestamp,
workspace_actions: Default::default(), workspace_actions: Default::default(),
call_factory,
} }
} }
@ -697,7 +694,6 @@ impl Workspace {
abs_paths: Vec<PathBuf>, abs_paths: Vec<PathBuf>,
app_state: Arc<AppState>, app_state: Arc<AppState>,
requesting_window: Option<WindowHandle<Workspace>>, requesting_window: Option<WindowHandle<Workspace>>,
call_factory: CallFactory,
cx: &mut AppContext, cx: &mut AppContext,
) -> Task< ) -> Task<
anyhow::Result<( anyhow::Result<(
@ -748,13 +744,7 @@ impl Workspace {
let window = if let Some(window) = requesting_window { let window = if let Some(window) = requesting_window {
cx.update_window(window.into(), |old_workspace, cx| { cx.update_window(window.into(), |old_workspace, cx| {
cx.replace_root_view(|cx| { cx.replace_root_view(|cx| {
Workspace::new( Workspace::new(workspace_id, project_handle.clone(), app_state.clone(), cx)
workspace_id,
project_handle.clone(),
app_state.clone(),
call_factory,
cx,
)
}); });
})?; })?;
window window
@ -800,13 +790,7 @@ impl Workspace {
let project_handle = project_handle.clone(); let project_handle = project_handle.clone();
move |cx| { move |cx| {
cx.build_view(|cx| { cx.build_view(|cx| {
Workspace::new( Workspace::new(workspace_id, project_handle, app_state, cx)
workspace_id,
project_handle,
app_state,
call_factory,
cx,
)
}) })
} }
})? })?
@ -1067,13 +1051,7 @@ impl Workspace {
if self.project.read(cx).is_local() { if self.project.read(cx).is_local() {
Task::Ready(Some(Ok(callback(self, cx)))) Task::Ready(Some(Ok(callback(self, cx))))
} else { } else {
let task = Self::new_local( let task = Self::new_local(Vec::new(), self.app_state.clone(), None, cx);
Vec::new(),
self.app_state.clone(),
None,
self.call_factory,
cx,
);
cx.spawn(|_vh, mut cx| async move { cx.spawn(|_vh, mut cx| async move {
let (workspace, _) = task.await?; let (workspace, _) = task.await?;
workspace.update(&mut cx, callback) workspace.update(&mut cx, callback)
@ -1302,7 +1280,7 @@ impl Workspace {
Some(self.prepare_to_close(false, cx)) Some(self.prepare_to_close(false, cx))
}; };
let app_state = self.app_state.clone(); let app_state = self.app_state.clone();
let call_factory = self.call_factory;
cx.spawn(|_, mut cx| async move { cx.spawn(|_, mut cx| async move {
let window_to_replace = if let Some(close_task) = close_task { let window_to_replace = if let Some(close_task) = close_task {
if !close_task.await? { if !close_task.await? {
@ -1312,7 +1290,7 @@ impl Workspace {
} else { } else {
None None
}; };
cx.update(|_, cx| open_paths(&paths, &app_state, window_to_replace, call_factory, cx))? cx.update(|_, cx| open_paths(&paths, &app_state, window_to_replace, cx))?
.await?; .await?;
Ok(()) Ok(())
}) })
@ -2282,7 +2260,7 @@ impl Workspace {
} }
fn collaborator_left(&mut self, peer_id: PeerId, cx: &mut ViewContext<Self>) { fn collaborator_left(&mut self, peer_id: PeerId, cx: &mut ViewContext<Self>) {
self.call_handler.follower_states_mut().retain(|_, state| { self.follower_states.retain(|_, state| {
if state.leader_id == peer_id { if state.leader_id == peer_id {
for item in state.items_by_leader_view_id.values() { for item in state.items_by_leader_view_id.values() {
item.set_leader_peer_id(None, cx); item.set_leader_peer_id(None, cx);
@ -2435,7 +2413,7 @@ impl Workspace {
// } // }
pub fn unfollow(&mut self, pane: &View<Pane>, cx: &mut ViewContext<Self>) -> Option<PeerId> { pub fn unfollow(&mut self, pane: &View<Pane>, cx: &mut ViewContext<Self>) -> Option<PeerId> {
let follower_states = self.call_handler.follower_states_mut(); let follower_states = &mut self.follower_states;
let state = follower_states.remove(pane)?; let state = follower_states.remove(pane)?;
let leader_id = state.leader_id; let leader_id = state.leader_id;
for (_, item) in state.items_by_leader_view_id { for (_, item) in state.items_by_leader_view_id {
@ -2658,7 +2636,7 @@ impl Workspace {
match update.variant.ok_or_else(|| anyhow!("invalid update"))? { match update.variant.ok_or_else(|| anyhow!("invalid update"))? {
proto::update_followers::Variant::UpdateActiveView(update_active_view) => { proto::update_followers::Variant::UpdateActiveView(update_active_view) => {
this.update(cx, |this, _| { this.update(cx, |this, _| {
for (_, state) in this.call_handler.follower_states_mut() { for (_, state) in &mut this.follower_states {
if state.leader_id == leader_id { if state.leader_id == leader_id {
state.active_view_id = state.active_view_id =
if let Some(active_view_id) = update_active_view.id.clone() { if let Some(active_view_id) = update_active_view.id.clone() {
@ -2681,7 +2659,7 @@ impl Workspace {
let mut tasks = Vec::new(); let mut tasks = Vec::new();
this.update(cx, |this, cx| { this.update(cx, |this, cx| {
let project = this.project.clone(); let project = this.project.clone();
for (_, state) in this.call_handler.follower_states_mut() { for (_, state) in &mut this.follower_states {
if state.leader_id == leader_id { if state.leader_id == leader_id {
let view_id = ViewId::from_proto(id.clone())?; let view_id = ViewId::from_proto(id.clone())?;
if let Some(item) = state.items_by_leader_view_id.get(&view_id) { if let Some(item) = state.items_by_leader_view_id.get(&view_id) {
@ -2695,8 +2673,7 @@ impl Workspace {
} }
proto::update_followers::Variant::CreateView(view) => { proto::update_followers::Variant::CreateView(view) => {
let panes = this.update(cx, |this, _| { let panes = this.update(cx, |this, _| {
this.call_handler this.follower_states
.follower_states()
.iter() .iter()
.filter_map(|(pane, state)| (state.leader_id == leader_id).then_some(pane)) .filter_map(|(pane, state)| (state.leader_id == leader_id).then_some(pane))
.cloned() .cloned()
@ -2756,7 +2733,7 @@ impl Workspace {
for (pane, (item_tasks, leader_view_ids)) in item_tasks_by_pane { for (pane, (item_tasks, leader_view_ids)) in item_tasks_by_pane {
let items = futures::future::try_join_all(item_tasks).await?; let items = futures::future::try_join_all(item_tasks).await?;
this.update(cx, |this, cx| { this.update(cx, |this, cx| {
let state = this.call_handler.follower_states_mut().get_mut(&pane)?; let state = this.follower_states.get_mut(&pane)?;
for (id, item) in leader_view_ids.into_iter().zip(items) { for (id, item) in leader_view_ids.into_iter().zip(items) {
item.set_leader_peer_id(Some(leader_id), cx); item.set_leader_peer_id(Some(leader_id), cx);
state.items_by_leader_view_id.insert(id, item); state.items_by_leader_view_id.insert(id, item);
@ -2813,14 +2790,55 @@ impl Workspace {
} }
pub fn leader_for_pane(&self, pane: &View<Pane>) -> Option<PeerId> { pub fn leader_for_pane(&self, pane: &View<Pane>) -> Option<PeerId> {
self.call_handler self.follower_states.get(pane).map(|state| state.leader_id)
.follower_states()
.get(pane)
.map(|state| state.leader_id)
} }
fn leader_updated(&mut self, leader_id: PeerId, cx: &mut ViewContext<Self>) -> Option<()> { pub fn leader_updated(&mut self, leader_id: PeerId, cx: &mut ViewContext<Self>) -> Option<()> {
self.call_handler.leader_updated(leader_id, cx) cx.notify();
let (leader_in_this_project, leader_in_this_app) =
self.call_handler.peer_state(leader_id, cx)?;
let mut items_to_activate = Vec::new();
for (pane, state) in &self.follower_states {
if state.leader_id != leader_id {
continue;
}
if let (Some(active_view_id), true) = (state.active_view_id, leader_in_this_app) {
if let Some(item) = state.items_by_leader_view_id.get(&active_view_id) {
if leader_in_this_project || !item.is_project_item(cx) {
items_to_activate.push((pane.clone(), item.boxed_clone()));
}
} else {
log::warn!(
"unknown view id {:?} for leader {:?}",
active_view_id,
leader_id
);
}
continue;
}
// todo!()
// if let Some(shared_screen) = self.shared_screen_for_peer(leader_id, pane, cx) {
// items_to_activate.push((pane.clone(), Box::new(shared_screen)));
// }
}
for (pane, item) in items_to_activate {
let pane_was_focused = pane.read(cx).has_focus(cx);
if let Some(index) = pane.update(cx, |pane, _| pane.index_for_item(item.as_ref())) {
pane.update(cx, |pane, cx| pane.activate_item(index, false, false, cx));
} else {
pane.update(cx, |pane, mut cx| {
pane.add_item(item.boxed_clone(), false, false, None, &mut cx)
});
}
if pane_was_focused {
pane.update(cx, |pane, cx| pane.focus_active_item(cx));
}
}
None
} }
// todo!() // todo!()
@ -3637,7 +3655,7 @@ impl Render for Workspace {
.flex_1() .flex_1()
.child(self.center.render( .child(self.center.render(
&self.project, &self.project,
&self.call_handler.follower_states(), &self.follower_states,
&self.active_pane, &self.active_pane,
self.zoomed.as_ref(), self.zoomed.as_ref(),
&self.app_state, &self.app_state,
@ -4201,7 +4219,6 @@ pub fn open_paths(
abs_paths: &[PathBuf], abs_paths: &[PathBuf],
app_state: &Arc<AppState>, app_state: &Arc<AppState>,
requesting_window: Option<WindowHandle<Workspace>>, requesting_window: Option<WindowHandle<Workspace>>,
call_factory: CallFactory,
cx: &mut AppContext, cx: &mut AppContext,
) -> Task< ) -> Task<
anyhow::Result<( anyhow::Result<(
@ -4228,13 +4245,7 @@ pub fn open_paths(
todo!() todo!()
} else { } else {
cx.update(move |cx| { cx.update(move |cx| {
Workspace::new_local( Workspace::new_local(abs_paths, app_state.clone(), requesting_window, cx)
abs_paths,
app_state.clone(),
requesting_window,
call_factory,
cx,
)
})? })?
.await .await
} }
@ -4245,9 +4256,8 @@ pub fn open_new(
app_state: &Arc<AppState>, app_state: &Arc<AppState>,
cx: &mut AppContext, cx: &mut AppContext,
init: impl FnOnce(&mut Workspace, &mut ViewContext<Workspace>) + 'static + Send, init: impl FnOnce(&mut Workspace, &mut ViewContext<Workspace>) + 'static + Send,
call_factory: CallFactory,
) -> Task<()> { ) -> Task<()> {
let task = Workspace::new_local(Vec::new(), app_state.clone(), None, call_factory, cx); let task = Workspace::new_local(Vec::new(), app_state.clone(), None, cx);
cx.spawn(|mut cx| async move { cx.spawn(|mut cx| async move {
if let Some((workspace, opened_paths)) = task.await.log_err() { if let Some((workspace, opened_paths)) = task.await.log_err() {
workspace workspace

View file

@ -189,7 +189,7 @@ fn main() {
// audio::init(Assets, cx); // audio::init(Assets, cx);
auto_update::init(http.clone(), client::ZED_SERVER_URL.clone(), cx); auto_update::init(http.clone(), client::ZED_SERVER_URL.clone(), cx);
workspace::init(app_state.clone(), cx); workspace::init(app_state.clone(), cx, call::Call::new);
// recent_projects::init(cx); // recent_projects::init(cx);
go_to_line::init(cx); go_to_line::init(cx);