Add following into channel notes
co-authored-by: max <max@zed.dev>
This commit is contained in:
parent
7e83138805
commit
199be8241c
6 changed files with 128 additions and 17 deletions
|
@ -1,27 +1,34 @@
|
||||||
use channel::channel_buffer::ChannelBuffer;
|
use channel::channel_buffer::ChannelBuffer;
|
||||||
|
use client::proto;
|
||||||
use clock::ReplicaId;
|
use clock::ReplicaId;
|
||||||
use collections::HashMap;
|
use collections::HashMap;
|
||||||
use editor::Editor;
|
use editor::Editor;
|
||||||
use gpui::{
|
use gpui::{
|
||||||
actions,
|
actions,
|
||||||
elements::{ChildView, Label},
|
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 language::Language;
|
||||||
use project::Project;
|
use project::Project;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use workspace::item::{Item, ItemHandle};
|
use workspace::{
|
||||||
|
item::{FollowableItem, Item, ItemHandle},
|
||||||
|
register_followable_item, ViewId,
|
||||||
|
};
|
||||||
|
|
||||||
actions!(channel_view, [Deploy]);
|
actions!(channel_view, [Deploy]);
|
||||||
|
|
||||||
pub(crate) fn init(cx: &mut AppContext) {
|
pub(crate) fn init(cx: &mut AppContext) {
|
||||||
// TODO
|
register_followable_item::<ChannelView>(cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ChannelView {
|
pub struct ChannelView {
|
||||||
editor: ViewHandle<Editor>,
|
editor: ViewHandle<Editor>,
|
||||||
project: ModelHandle<Project>,
|
project: ModelHandle<Project>,
|
||||||
channel_buffer: ModelHandle<ChannelBuffer>,
|
channel_buffer: ModelHandle<ChannelBuffer>,
|
||||||
|
remote_id: Option<ViewId>,
|
||||||
|
_editor_event_subscription: Subscription,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ChannelView {
|
impl ChannelView {
|
||||||
|
@ -34,14 +41,19 @@ impl ChannelView {
|
||||||
let buffer = channel_buffer.read(cx).buffer();
|
let buffer = channel_buffer.read(cx).buffer();
|
||||||
buffer.update(cx, |buffer, cx| buffer.set_language(language, cx));
|
buffer.update(cx, |buffer, cx| buffer.set_language(language, cx));
|
||||||
let editor = cx.add_view(|cx| Editor::for_buffer(buffer, None, 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 {
|
let this = Self {
|
||||||
editor,
|
editor,
|
||||||
project,
|
project,
|
||||||
channel_buffer,
|
channel_buffer,
|
||||||
|
remote_id: None,
|
||||||
|
_editor_event_subscription,
|
||||||
};
|
};
|
||||||
let mapping = this.project_replica_ids_by_channel_buffer_replica_id(cx);
|
let mapping = this.project_replica_ids_by_channel_buffer_replica_id(cx);
|
||||||
this.editor
|
this.editor
|
||||||
.update(cx, |editor, cx| editor.set_replica_id_mapping(mapping, cx));
|
.update(cx, |editor, cx| editor.set_replica_id_mapping(mapping, cx));
|
||||||
|
|
||||||
this
|
this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,9 +94,15 @@ impl View for ChannelView {
|
||||||
"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()
|
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 {
|
impl Item for ChannelView {
|
||||||
|
@ -104,3 +122,85 @@ impl Item for ChannelView {
|
||||||
Label::new(channel_name, style.label.to_owned()).into_any()
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -6384,7 +6384,7 @@ async fn test_following_with_multiple_excerpts(cx: &mut gpui::TestAppContext) {
|
||||||
.update(|cx| {
|
.update(|cx| {
|
||||||
Editor::from_state_proto(
|
Editor::from_state_proto(
|
||||||
pane.clone(),
|
pane.clone(),
|
||||||
project.clone(),
|
workspace.clone(),
|
||||||
ViewId {
|
ViewId {
|
||||||
creator: Default::default(),
|
creator: Default::default(),
|
||||||
id: 0,
|
id: 0,
|
||||||
|
@ -6479,7 +6479,7 @@ async fn test_following_with_multiple_excerpts(cx: &mut gpui::TestAppContext) {
|
||||||
.update(|cx| {
|
.update(|cx| {
|
||||||
Editor::from_state_proto(
|
Editor::from_state_proto(
|
||||||
pane.clone(),
|
pane.clone(),
|
||||||
project.clone(),
|
workspace.clone(),
|
||||||
ViewId {
|
ViewId {
|
||||||
creator: Default::default(),
|
creator: Default::default(),
|
||||||
id: 0,
|
id: 0,
|
||||||
|
|
|
@ -49,11 +49,12 @@ impl FollowableItem for Editor {
|
||||||
|
|
||||||
fn from_state_proto(
|
fn from_state_proto(
|
||||||
pane: ViewHandle<workspace::Pane>,
|
pane: ViewHandle<workspace::Pane>,
|
||||||
project: ModelHandle<Project>,
|
workspace: ViewHandle<Workspace>,
|
||||||
remote_id: ViewId,
|
remote_id: ViewId,
|
||||||
state: &mut Option<proto::view::Variant>,
|
state: &mut Option<proto::view::Variant>,
|
||||||
cx: &mut AppContext,
|
cx: &mut AppContext,
|
||||||
) -> Option<Task<Result<ViewHandle<Self>>>> {
|
) -> 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 else { return None };
|
||||||
let Some(proto::view::Variant::Editor(state)) = state.take() else { unreachable!() };
|
let Some(proto::view::Variant::Editor(state)) = state.take() else { unreachable!() };
|
||||||
|
|
||||||
|
|
|
@ -1120,6 +1120,7 @@ message View {
|
||||||
|
|
||||||
oneof variant {
|
oneof variant {
|
||||||
Editor editor = 3;
|
Editor editor = 3;
|
||||||
|
ChannelView channel_view = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
message Editor {
|
message Editor {
|
||||||
|
@ -1132,6 +1133,10 @@ message View {
|
||||||
float scroll_x = 7;
|
float scroll_x = 7;
|
||||||
float scroll_y = 8;
|
float scroll_y = 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message ChannelView {
|
||||||
|
uint64 channel_id = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
message Collaborator {
|
message Collaborator {
|
||||||
|
|
|
@ -674,7 +674,7 @@ pub trait FollowableItem: Item {
|
||||||
fn to_state_proto(&self, cx: &AppContext) -> Option<proto::view::Variant>;
|
fn to_state_proto(&self, cx: &AppContext) -> Option<proto::view::Variant>;
|
||||||
fn from_state_proto(
|
fn from_state_proto(
|
||||||
pane: ViewHandle<Pane>,
|
pane: ViewHandle<Pane>,
|
||||||
project: ModelHandle<Project>,
|
project: ViewHandle<Workspace>,
|
||||||
id: ViewId,
|
id: ViewId,
|
||||||
state: &mut Option<proto::view::Variant>,
|
state: &mut Option<proto::view::Variant>,
|
||||||
cx: &mut AppContext,
|
cx: &mut AppContext,
|
||||||
|
|
|
@ -345,7 +345,7 @@ pub fn register_project_item<I: ProjectItem>(cx: &mut AppContext) {
|
||||||
|
|
||||||
type FollowableItemBuilder = fn(
|
type FollowableItemBuilder = fn(
|
||||||
ViewHandle<Pane>,
|
ViewHandle<Pane>,
|
||||||
ModelHandle<Project>,
|
ViewHandle<Workspace>,
|
||||||
ViewId,
|
ViewId,
|
||||||
&mut Option<proto::view::Variant>,
|
&mut Option<proto::view::Variant>,
|
||||||
&mut AppContext,
|
&mut AppContext,
|
||||||
|
@ -362,8 +362,8 @@ pub fn register_followable_item<I: FollowableItem>(cx: &mut AppContext) {
|
||||||
builders.insert(
|
builders.insert(
|
||||||
TypeId::of::<I>(),
|
TypeId::of::<I>(),
|
||||||
(
|
(
|
||||||
|pane, project, id, state, cx| {
|
|pane, workspace, id, state, cx| {
|
||||||
I::from_state_proto(pane, project, id, state, cx).map(|task| {
|
I::from_state_proto(pane, workspace, id, state, cx).map(|task| {
|
||||||
cx.foreground()
|
cx.foreground()
|
||||||
.spawn(async move { Ok(Box::new(task.await?) as Box<_>) })
|
.spawn(async move { Ok(Box::new(task.await?) as Box<_>) })
|
||||||
})
|
})
|
||||||
|
@ -2848,7 +2848,13 @@ impl Workspace {
|
||||||
views: Vec<proto::View>,
|
views: Vec<proto::View>,
|
||||||
cx: &mut AsyncAppContext,
|
cx: &mut AsyncAppContext,
|
||||||
) -> Result<()> {
|
) -> 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
|
let replica_id = project
|
||||||
.read_with(cx, |project, _| {
|
.read_with(cx, |project, _| {
|
||||||
project
|
project
|
||||||
|
@ -2874,12 +2880,11 @@ impl Workspace {
|
||||||
let id = ViewId::from_proto(id.clone())?;
|
let id = ViewId::from_proto(id.clone())?;
|
||||||
let mut variant = view.variant.clone();
|
let mut variant = view.variant.clone();
|
||||||
if variant.is_none() {
|
if variant.is_none() {
|
||||||
Err(anyhow!("missing variant"))?;
|
Err(anyhow!("missing view variant"))?;
|
||||||
}
|
}
|
||||||
for build_item in &item_builders {
|
for build_item in &item_builders {
|
||||||
let task = cx.update(|cx| {
|
let task = cx
|
||||||
build_item(pane.clone(), project.clone(), id, &mut variant, cx)
|
.update(|cx| build_item(pane.clone(), this.clone(), id, &mut variant, cx));
|
||||||
});
|
|
||||||
if let Some(task) = task {
|
if let Some(task) = task {
|
||||||
item_tasks.push(task);
|
item_tasks.push(task);
|
||||||
leader_view_ids.push(id);
|
leader_view_ids.push(id);
|
||||||
|
@ -2907,7 +2912,7 @@ impl Workspace {
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(())
|
Some(())
|
||||||
})?;
|
});
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue