Add following into channel notes

co-authored-by: max <max@zed.dev>
This commit is contained in:
Mikayla 2023-08-24 11:25:20 -07:00
parent 7e83138805
commit 199be8241c
No known key found for this signature in database
6 changed files with 128 additions and 17 deletions

View File

@ -1,27 +1,34 @@
use channel::channel_buffer::ChannelBuffer;
use client::proto;
use clock::ReplicaId;
use collections::HashMap;
use editor::Editor;
use gpui::{
actions,
elements::{ChildView, Label},
AnyElement, AppContext, Element, Entity, ModelHandle, View, ViewContext, ViewHandle,
AnyElement, AnyViewHandle, AppContext, Element, Entity, ModelHandle, Subscription, View,
ViewContext, ViewHandle,
};
use language::Language;
use project::Project;
use std::sync::Arc;
use workspace::item::{Item, ItemHandle};
use workspace::{
item::{FollowableItem, Item, ItemHandle},
register_followable_item, ViewId,
};
actions!(channel_view, [Deploy]);
pub(crate) fn init(cx: &mut AppContext) {
// TODO
register_followable_item::<ChannelView>(cx)
}
pub struct ChannelView {
editor: ViewHandle<Editor>,
project: ModelHandle<Project>,
channel_buffer: ModelHandle<ChannelBuffer>,
remote_id: Option<ViewId>,
_editor_event_subscription: Subscription,
}
impl ChannelView {
@ -34,14 +41,19 @@ impl ChannelView {
let buffer = channel_buffer.read(cx).buffer();
buffer.update(cx, |buffer, cx| buffer.set_language(language, cx));
let editor = cx.add_view(|cx| Editor::for_buffer(buffer, None, cx));
let _editor_event_subscription = cx.subscribe(&editor, |_, _, e, cx| cx.emit(e.clone()));
let this = Self {
editor,
project,
channel_buffer,
remote_id: None,
_editor_event_subscription,
};
let mapping = this.project_replica_ids_by_channel_buffer_replica_id(cx);
this.editor
.update(cx, |editor, cx| editor.set_replica_id_mapping(mapping, cx));
this
}
@ -82,9 +94,15 @@ impl View for ChannelView {
"ChannelView"
}
fn render(&mut self, cx: &mut ViewContext<'_, '_, Self>) -> AnyElement<Self> {
fn render(&mut self, cx: &mut ViewContext<Self>) -> AnyElement<Self> {
ChildView::new(self.editor.as_any(), cx).into_any()
}
fn focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext<Self>) {
if cx.is_self_focused() {
cx.focus(self.editor.as_any())
}
}
}
impl Item for ChannelView {
@ -104,3 +122,85 @@ impl Item for ChannelView {
Label::new(channel_name, style.label.to_owned()).into_any()
}
}
impl FollowableItem for ChannelView {
fn remote_id(&self) -> Option<workspace::ViewId> {
self.remote_id
}
fn to_state_proto(&self, cx: &AppContext) -> Option<proto::view::Variant> {
self.channel_buffer.read(cx).channel(cx).map(|channel| {
proto::view::Variant::ChannelView(proto::view::ChannelView {
channel_id: channel.id,
})
})
}
fn from_state_proto(
_: ViewHandle<workspace::Pane>,
workspace: ViewHandle<workspace::Workspace>,
remote_id: workspace::ViewId,
state_proto: &mut Option<proto::view::Variant>,
cx: &mut AppContext,
) -> Option<gpui::Task<anyhow::Result<ViewHandle<Self>>>> {
let Some(proto::view::Variant::ChannelView(_)) = state_proto else { return None };
let Some(proto::view::Variant::ChannelView(state)) = state_proto.take() else { unreachable!() };
let channel_store = &workspace.read(cx).app_state().channel_store.clone();
let open_channel_buffer = channel_store.update(cx, |store, cx| {
store.open_channel_buffer(state.channel_id, cx)
});
let project = workspace.read(cx).project().to_owned();
let language = workspace.read(cx).app_state().languages.clone();
let get_markdown = language.language_for_name("Markdown");
Some(cx.spawn(|mut cx| async move {
let channel_buffer = open_channel_buffer.await?;
let markdown = get_markdown.await?;
let this = workspace
.update(&mut cx, move |_, cx| {
cx.add_view(|cx| {
let mut this = Self::new(project, channel_buffer, Some(markdown), cx);
this.remote_id = Some(remote_id);
this
})
})
.ok_or_else(|| anyhow::anyhow!("workspace droppped"))?;
Ok(this)
}))
}
fn add_event_to_update_proto(
&self,
_: &Self::Event,
_: &mut Option<proto::update_view::Variant>,
_: &AppContext,
) -> bool {
false
}
fn apply_update_proto(
&mut self,
_: &ModelHandle<Project>,
_: proto::update_view::Variant,
_: &mut ViewContext<Self>,
) -> gpui::Task<anyhow::Result<()>> {
gpui::Task::ready(Ok(()))
}
fn set_leader_replica_id(
&mut self,
leader_replica_id: Option<u16>,
cx: &mut ViewContext<Self>,
) {
self.editor.update(cx, |editor, cx| {
editor.set_leader_replica_id(leader_replica_id, cx)
})
}
fn should_unfollow_on_event(event: &Self::Event, cx: &AppContext) -> bool {
Editor::should_unfollow_on_event(event, cx)
}
}

View File

@ -6384,7 +6384,7 @@ async fn test_following_with_multiple_excerpts(cx: &mut gpui::TestAppContext) {
.update(|cx| {
Editor::from_state_proto(
pane.clone(),
project.clone(),
workspace.clone(),
ViewId {
creator: Default::default(),
id: 0,
@ -6479,7 +6479,7 @@ async fn test_following_with_multiple_excerpts(cx: &mut gpui::TestAppContext) {
.update(|cx| {
Editor::from_state_proto(
pane.clone(),
project.clone(),
workspace.clone(),
ViewId {
creator: Default::default(),
id: 0,

View File

@ -49,11 +49,12 @@ impl FollowableItem for Editor {
fn from_state_proto(
pane: ViewHandle<workspace::Pane>,
project: ModelHandle<Project>,
workspace: ViewHandle<Workspace>,
remote_id: ViewId,
state: &mut Option<proto::view::Variant>,
cx: &mut AppContext,
) -> Option<Task<Result<ViewHandle<Self>>>> {
let project = workspace.read(cx).project().to_owned();
let Some(proto::view::Variant::Editor(_)) = state else { return None };
let Some(proto::view::Variant::Editor(state)) = state.take() else { unreachable!() };

View File

@ -1120,6 +1120,7 @@ message View {
oneof variant {
Editor editor = 3;
ChannelView channel_view = 4;
}
message Editor {
@ -1132,6 +1133,10 @@ message View {
float scroll_x = 7;
float scroll_y = 8;
}
message ChannelView {
uint64 channel_id = 1;
}
}
message Collaborator {

View File

@ -674,7 +674,7 @@ pub trait FollowableItem: Item {
fn to_state_proto(&self, cx: &AppContext) -> Option<proto::view::Variant>;
fn from_state_proto(
pane: ViewHandle<Pane>,
project: ModelHandle<Project>,
project: ViewHandle<Workspace>,
id: ViewId,
state: &mut Option<proto::view::Variant>,
cx: &mut AppContext,

View File

@ -345,7 +345,7 @@ pub fn register_project_item<I: ProjectItem>(cx: &mut AppContext) {
type FollowableItemBuilder = fn(
ViewHandle<Pane>,
ModelHandle<Project>,
ViewHandle<Workspace>,
ViewId,
&mut Option<proto::view::Variant>,
&mut AppContext,
@ -362,8 +362,8 @@ pub fn register_followable_item<I: FollowableItem>(cx: &mut AppContext) {
builders.insert(
TypeId::of::<I>(),
(
|pane, project, id, state, cx| {
I::from_state_proto(pane, project, id, state, cx).map(|task| {
|pane, workspace, id, state, cx| {
I::from_state_proto(pane, workspace, id, state, cx).map(|task| {
cx.foreground()
.spawn(async move { Ok(Box::new(task.await?) as Box<_>) })
})
@ -2848,7 +2848,13 @@ impl Workspace {
views: Vec<proto::View>,
cx: &mut AsyncAppContext,
) -> Result<()> {
let project = this.read_with(cx, |this, _| this.project.clone())?;
let this = this
.upgrade(cx)
.ok_or_else(|| anyhow!("workspace dropped"))?;
let project = this
.read_with(cx, |this, _| this.project.clone())
.ok_or_else(|| anyhow!("window dropped"))?;
let replica_id = project
.read_with(cx, |project, _| {
project
@ -2874,12 +2880,11 @@ impl Workspace {
let id = ViewId::from_proto(id.clone())?;
let mut variant = view.variant.clone();
if variant.is_none() {
Err(anyhow!("missing variant"))?;
Err(anyhow!("missing view variant"))?;
}
for build_item in &item_builders {
let task = cx.update(|cx| {
build_item(pane.clone(), project.clone(), id, &mut variant, cx)
});
let task = cx
.update(|cx| build_item(pane.clone(), this.clone(), id, &mut variant, cx));
if let Some(task) = task {
item_tasks.push(task);
leader_view_ids.push(id);
@ -2907,7 +2912,7 @@ impl Workspace {
}
Some(())
})?;
});
}
Ok(())
}