Start work on following in zed2

Co-authored-by: Nathan <nathan@zed.dev>
This commit is contained in:
Max Brunsfeld 2023-12-04 17:51:53 -08:00
parent 71a1125e88
commit eff3a72fb5
4 changed files with 245 additions and 167 deletions

View file

@ -1165,12 +1165,11 @@ impl CollabPanel {
div().into_any_element() div().into_any_element()
}), }),
) )
.when(!is_current_user, |this| { .when_some(peer_id, |this, peer_id| {
this.tooltip(move |cx| Tooltip::text(tooltip.clone(), cx)) this.tooltip(move |cx| Tooltip::text(tooltip.clone(), cx))
.on_click(cx.listener(move |this, _, cx| { .on_click(cx.listener(move |this, _, cx| {
this.workspace.update(cx, |workspace, cx| { this.workspace
// workspace.follow(peer_id, cx) .update(cx, |workspace, cx| workspace.follow(peer_id, cx));
});
})) }))
}) })
} }

View file

@ -2708,6 +2708,7 @@ pub enum ElementId {
Integer(usize), Integer(usize),
Name(SharedString), Name(SharedString),
FocusHandle(FocusId), FocusHandle(FocusId),
NamedInteger(SharedString, usize),
} }
impl ElementId { impl ElementId {
@ -2757,3 +2758,9 @@ impl<'a> From<&'a FocusHandle> for ElementId {
ElementId::FocusHandle(handle.id) ElementId::FocusHandle(handle.id)
} }
} }
impl From<(&'static str, EntityId)> for ElementId {
fn from((name, id): (&'static str, EntityId)) -> Self {
ElementId::NamedInteger(name.into(), id.as_u64() as usize)
}
}

View file

@ -1,19 +1,20 @@
use crate::{AppState, FollowerState, Pane, Workspace}; use crate::{AppState, FollowerState, Pane, Workspace};
use anyhow::{anyhow, bail, Result}; use anyhow::{anyhow, bail, Result};
use call::ActiveCall; use call::{ActiveCall, ParticipantLocation};
use collections::HashMap; use collections::HashMap;
use db::sqlez::{ use db::sqlez::{
bindable::{Bind, Column, StaticColumnCount}, bindable::{Bind, Column, StaticColumnCount},
statement::Statement, statement::Statement,
}; };
use gpui::{ use gpui::{
point, size, AnyWeakView, Bounds, Div, IntoElement, Model, Pixels, Point, View, ViewContext, point, size, AnyWeakView, Bounds, Div, Entity as _, IntoElement, Model, Pixels, Point, View,
ViewContext,
}; };
use parking_lot::Mutex; use parking_lot::Mutex;
use project::Project; use project::Project;
use serde::Deserialize; use serde::Deserialize;
use std::sync::Arc; use std::sync::Arc;
use ui::prelude::*; use ui::{prelude::*, Button};
const HANDLE_HITBOX_SIZE: f32 = 4.0; const HANDLE_HITBOX_SIZE: f32 = 4.0;
const HORIZONTAL_MIN_SIZE: f32 = 80.; const HORIZONTAL_MIN_SIZE: f32 = 80.;
@ -207,19 +208,89 @@ impl Member {
) -> impl IntoElement { ) -> impl IntoElement {
match self { match self {
Member::Pane(pane) => { Member::Pane(pane) => {
// todo!() let leader = follower_states.get(pane).and_then(|state| {
// let pane_element = if Some(pane.into()) == zoomed { let room = active_call?.read(cx).room()?.read(cx);
// None room.remote_participant_for_peer_id(state.leader_id)
// } else { });
// Some(pane)
// };
div().size_full().child(pane.clone()).into_any() let mut leader_border = None;
let mut leader_status_box = None;
if let Some(leader) = &leader {
let mut leader_color = cx
.theme()
.players()
.color_for_participant(leader.participant_index.0)
.cursor;
leader_color.fade_out(0.3);
leader_border = Some(leader_color);
// Stack::new() leader_status_box = match leader.location {
// .with_child(pane_element.contained().with_border(leader_border)) ParticipantLocation::SharedProject {
// .with_children(leader_status_box) project_id: leader_project_id,
// .into_any() } => {
if Some(leader_project_id) == project.read(cx).remote_id() {
None
} else {
let leader_user = leader.user.clone();
let leader_user_id = leader.user.id;
Some(
Button::new(
("leader-status", pane.entity_id()),
format!(
"Follow {} to their active project",
leader_user.github_login,
),
)
.on_click(cx.listener(
move |this, _, cx| {
crate::join_remote_project(
leader_project_id,
leader_user_id,
this.app_state().clone(),
cx,
)
.detach_and_log_err(cx);
},
)),
)
}
}
ParticipantLocation::UnsharedProject => Some(Button::new(
("leader-status", pane.entity_id()),
format!(
"{} is viewing an unshared Zed project",
leader.user.github_login
),
)),
ParticipantLocation::External => Some(Button::new(
("leader-status", pane.entity_id()),
format!(
"{} is viewing a window outside of Zed",
leader.user.github_login
),
)),
};
}
div()
.relative()
.size_full()
.child(pane.clone())
.when_some(leader_border, |this, color| {
this.border_2().border_color(color)
})
.when_some(leader_status_box, |this, status_box| {
this.child(
div()
.absolute()
.w_96()
.bottom_3()
.right_3()
.z_index(1)
.child(status_box),
)
})
.into_any()
// let el = div() // let el = div()
// .flex() // .flex()

View file

@ -2270,60 +2270,60 @@ impl Workspace {
cx.notify(); cx.notify();
} }
// fn start_following( fn start_following(
// &mut self, &mut self,
// leader_id: PeerId, leader_id: PeerId,
// cx: &mut ViewContext<Self>, cx: &mut ViewContext<Self>,
// ) -> Option<Task<Result<()>>> { ) -> Option<Task<Result<()>>> {
// let pane = self.active_pane().clone(); let pane = self.active_pane().clone();
// self.last_leaders_by_pane self.last_leaders_by_pane
// .insert(pane.downgrade(), leader_id); .insert(pane.downgrade(), leader_id);
// self.unfollow(&pane, cx); self.unfollow(&pane, cx);
// self.follower_states.insert( self.follower_states.insert(
// pane.clone(), pane.clone(),
// FollowerState { FollowerState {
// leader_id, leader_id,
// active_view_id: None, active_view_id: None,
// items_by_leader_view_id: Default::default(), items_by_leader_view_id: Default::default(),
// }, },
// ); );
// cx.notify(); cx.notify();
// let room_id = self.active_call()?.read(cx).room()?.read(cx).id(); let room_id = self.active_call()?.read(cx).room()?.read(cx).id();
// let project_id = self.project.read(cx).remote_id(); let project_id = self.project.read(cx).remote_id();
// let request = self.app_state.client.request(proto::Follow { let request = self.app_state.client.request(proto::Follow {
// room_id, room_id,
// project_id, project_id,
// leader_id: Some(leader_id), leader_id: Some(leader_id),
// }); });
// Some(cx.spawn(|this, mut cx| async move { Some(cx.spawn(|this, mut cx| async move {
// let response = request.await?; let response = request.await?;
// this.update(&mut cx, |this, _| { this.update(&mut cx, |this, _| {
// let state = this let state = this
// .follower_states .follower_states
// .get_mut(&pane) .get_mut(&pane)
// .ok_or_else(|| anyhow!("following interrupted"))?; .ok_or_else(|| anyhow!("following interrupted"))?;
// state.active_view_id = if let Some(active_view_id) = response.active_view_id { state.active_view_id = if let Some(active_view_id) = response.active_view_id {
// Some(ViewId::from_proto(active_view_id)?) Some(ViewId::from_proto(active_view_id)?)
// } else { } else {
// None None
// }; };
// Ok::<_, anyhow::Error>(()) Ok::<_, anyhow::Error>(())
// })??; })??;
// Self::add_views_from_leader( Self::add_views_from_leader(
// this.clone(), this.clone(),
// leader_id, leader_id,
// vec![pane], vec![pane],
// response.views, response.views,
// &mut cx, &mut cx,
// ) )
// .await?; .await?;
// this.update(&mut cx, |this, cx| this.leader_updated(leader_id, cx))?; this.update(&mut cx, |this, cx| this.leader_updated(leader_id, cx))?;
// Ok(()) Ok(())
// })) }))
// } }
// pub fn follow_next_collaborator( // pub fn follow_next_collaborator(
// &mut self, // &mut self,
@ -2362,52 +2362,52 @@ impl Workspace {
// self.follow(leader_id, cx) // self.follow(leader_id, cx)
// } // }
// pub fn follow( pub fn follow(
// &mut self, &mut self,
// leader_id: PeerId, leader_id: PeerId,
// cx: &mut ViewContext<Self>, cx: &mut ViewContext<Self>,
// ) -> Option<Task<Result<()>>> { ) -> Option<Task<Result<()>>> {
// let room = ActiveCall::global(cx).read(cx).room()?.read(cx); let room = ActiveCall::global(cx).read(cx).room()?.read(cx);
// let project = self.project.read(cx); let project = self.project.read(cx);
// let Some(remote_participant) = room.remote_participant_for_peer_id(leader_id) else { let Some(remote_participant) = room.remote_participant_for_peer_id(leader_id) else {
// return None; return None;
// }; };
// let other_project_id = match remote_participant.location { let other_project_id = match remote_participant.location {
// call::ParticipantLocation::External => None, call::ParticipantLocation::External => None,
// call::ParticipantLocation::UnsharedProject => None, call::ParticipantLocation::UnsharedProject => None,
// call::ParticipantLocation::SharedProject { project_id } => { call::ParticipantLocation::SharedProject { project_id } => {
// if Some(project_id) == project.remote_id() { if Some(project_id) == project.remote_id() {
// None None
// } else { } else {
// Some(project_id) Some(project_id)
// } }
// } }
// }; };
// // if they are active in another project, follow there. // if they are active in another project, follow there.
// if let Some(project_id) = other_project_id { if let Some(project_id) = other_project_id {
// let app_state = self.app_state.clone(); let app_state = self.app_state.clone();
// return Some(crate::join_remote_project( return Some(crate::join_remote_project(
// project_id, project_id,
// remote_participant.user.id, remote_participant.user.id,
// app_state, app_state,
// cx, cx,
// )); ));
// } }
// // if you're already following, find the right pane and focus it. // if you're already following, find the right pane and focus it.
// for (pane, state) in &self.follower_states { for (pane, state) in &self.follower_states {
// if leader_id == state.leader_id { if leader_id == state.leader_id {
// cx.focus(pane); cx.focus_view(pane);
// return None; return None;
// } }
// } }
// // Otherwise, follow. // Otherwise, follow.
// self.start_following(leader_id, cx) self.start_following(leader_id, cx)
// } }
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 state = self.follower_states.remove(pane)?; let state = self.follower_states.remove(pane)?;
@ -2557,57 +2557,55 @@ impl Workspace {
} }
} }
// // RPC handlers // RPC handlers
fn handle_follow( fn handle_follow(
&mut self, &mut self,
_follower_project_id: Option<u64>, follower_project_id: Option<u64>,
_cx: &mut ViewContext<Self>, cx: &mut ViewContext<Self>,
) -> proto::FollowResponse { ) -> proto::FollowResponse {
todo!() let client = &self.app_state.client;
let project_id = self.project.read(cx).remote_id();
// let client = &self.app_state.client; let active_view_id = self.active_item(cx).and_then(|i| {
// let project_id = self.project.read(cx).remote_id(); Some(
i.to_followable_item_handle(cx)?
.remote_id(client, cx)?
.to_proto(),
)
});
// let active_view_id = self.active_item(cx).and_then(|i| { cx.notify();
// Some(
// i.to_followable_item_handle(cx)?
// .remote_id(client, cx)?
// .to_proto(),
// )
// });
// cx.notify(); self.last_active_view_id = active_view_id.clone();
proto::FollowResponse {
// self.last_active_view_id = active_view_id.clone(); active_view_id,
// proto::FollowResponse { views: self
// active_view_id, .panes()
// views: self .iter()
// .panes() .flat_map(|pane| {
// .iter() let leader_id = self.leader_for_pane(pane);
// .flat_map(|pane| { pane.read(cx).items().filter_map({
// let leader_id = self.leader_for_pane(pane); let cx = &cx;
// pane.read(cx).items().filter_map({ move |item| {
// let cx = &cx; let item = item.to_followable_item_handle(cx)?;
// move |item| { if (project_id.is_none() || project_id != follower_project_id)
// let item = item.to_followable_item_handle(cx)?; && item.is_project_item(cx)
// if (project_id.is_none() || project_id != follower_project_id) {
// && item.is_project_item(cx) return None;
// { }
// return None; let id = item.remote_id(client, cx)?.to_proto();
// } let variant = item.to_state_proto(cx)?;
// let id = item.remote_id(client, cx)?.to_proto(); Some(proto::View {
// let variant = item.to_state_proto(cx)?; id: Some(id),
// Some(proto::View { leader_id,
// id: Some(id), variant: Some(variant),
// leader_id, })
// variant: Some(variant), }
// }) })
// } })
// }) .collect(),
// }) }
// .collect(),
// }
} }
fn handle_update_followers( fn handle_update_followers(
@ -2627,6 +2625,8 @@ impl Workspace {
update: proto::UpdateFollowers, update: proto::UpdateFollowers,
cx: &mut AsyncWindowContext, cx: &mut AsyncWindowContext,
) -> Result<()> { ) -> Result<()> {
dbg!("process_leader_update", &update);
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, _| {
@ -3762,15 +3762,15 @@ impl Render for Workspace {
// } // }
impl WorkspaceStore { impl WorkspaceStore {
pub fn new(client: Arc<Client>, _cx: &mut ModelContext<Self>) -> Self { pub fn new(client: Arc<Client>, cx: &mut ModelContext<Self>) -> Self {
Self { Self {
workspaces: Default::default(), workspaces: Default::default(),
followers: Default::default(), followers: Default::default(),
_subscriptions: vec![], _subscriptions: vec![
// client.add_request_handler(cx.weak_model(), Self::handle_follow), client.add_request_handler(cx.weak_model(), Self::handle_follow),
// client.add_message_handler(cx.weak_model(), Self::handle_unfollow), client.add_message_handler(cx.weak_model(), Self::handle_unfollow),
// client.add_message_handler(cx.weak_model(), Self::handle_update_followers), client.add_message_handler(cx.weak_model(), Self::handle_update_followers),
// ], ],
client, client,
} }
} }
@ -3875,11 +3875,13 @@ impl WorkspaceStore {
this: Model<Self>, this: Model<Self>,
envelope: TypedEnvelope<proto::UpdateFollowers>, envelope: TypedEnvelope<proto::UpdateFollowers>,
_: Arc<Client>, _: Arc<Client>,
mut cx: AsyncWindowContext, mut cx: AsyncAppContext,
) -> Result<()> { ) -> Result<()> {
let leader_id = envelope.original_sender_id()?; let leader_id = envelope.original_sender_id()?;
let update = envelope.payload; let update = envelope.payload;
dbg!("handle_upate_followers");
this.update(&mut cx, |this, cx| { this.update(&mut cx, |this, cx| {
for workspace in &this.workspaces { for workspace in &this.workspaces {
workspace.update(cx, |workspace, cx| { workspace.update(cx, |workspace, cx| {
@ -4310,12 +4312,11 @@ pub fn join_remote_project(
Some(collaborator.peer_id) Some(collaborator.peer_id)
}); });
// todo!("uncomment following") if let Some(follow_peer_id) = follow_peer_id {
// if let Some(follow_peer_id) = follow_peer_id { workspace
// workspace .follow(follow_peer_id, cx)
// .follow(follow_peer_id, cx) .map(|follow| follow.detach_and_log_err(cx));
// .map(|follow| follow.detach_and_log_err(cx)); }
// }
} }
})?; })?;