// use anyhow::{anyhow, Result}; // use call::report_call_event_for_channel; // use channel::{Channel, ChannelBuffer, ChannelBufferEvent, ChannelId, ChannelStore}; // use client::{ // proto::{self, PeerId}, // Collaborator, ParticipantIndex, // }; // use collections::HashMap; // use editor::{CollaborationHub, Editor}; // use gpui::{ // actions, // elements::{ChildView, Label}, // geometry::vector::Vector2F, // AnyElement, AnyViewHandle, AppContext, Element, Entity, ModelHandle, Subscription, Task, View, // ViewContext, ViewHandle, // }; // use project::Project; // use smallvec::SmallVec; // use std::{ // any::{Any, TypeId}, // sync::Arc, // }; // use util::ResultExt; // use workspace::{ // item::{FollowableItem, Item, ItemEvent, ItemHandle}, // register_followable_item, // searchable::SearchableItemHandle, // ItemNavHistory, Pane, SaveIntent, ViewId, Workspace, WorkspaceId, // }; // actions!(channel_view, [Deploy]); // pub fn init(cx: &mut AppContext) { // register_followable_item::(cx) // } // pub struct ChannelView { // pub editor: ViewHandle, // project: ModelHandle, // channel_store: ModelHandle, // channel_buffer: ModelHandle, // remote_id: Option, // _editor_event_subscription: Subscription, // } // impl ChannelView { // pub fn open( // channel_id: ChannelId, // workspace: ViewHandle, // cx: &mut AppContext, // ) -> Task>> { // let pane = workspace.read(cx).active_pane().clone(); // let channel_view = Self::open_in_pane(channel_id, pane.clone(), workspace.clone(), cx); // cx.spawn(|mut cx| async move { // let channel_view = channel_view.await?; // pane.update(&mut cx, |pane, cx| { // report_call_event_for_channel( // "open channel notes", // channel_id, // &workspace.read(cx).app_state().client, // cx, // ); // pane.add_item(Box::new(channel_view.clone()), true, true, None, cx); // }); // anyhow::Ok(channel_view) // }) // } // pub fn open_in_pane( // channel_id: ChannelId, // pane: ViewHandle, // workspace: ViewHandle, // cx: &mut AppContext, // ) -> Task>> { // let workspace = workspace.read(cx); // let project = workspace.project().to_owned(); // let channel_store = ChannelStore::global(cx); // let language_registry = workspace.app_state().languages.clone(); // let markdown = language_registry.language_for_name("Markdown"); // let channel_buffer = // channel_store.update(cx, |store, cx| store.open_channel_buffer(channel_id, cx)); // cx.spawn(|mut cx| async move { // let channel_buffer = channel_buffer.await?; // let markdown = markdown.await.log_err(); // channel_buffer.update(&mut cx, |buffer, cx| { // buffer.buffer().update(cx, |buffer, cx| { // buffer.set_language_registry(language_registry); // if let Some(markdown) = markdown { // buffer.set_language(Some(markdown), cx); // } // }) // }); // pane.update(&mut cx, |pane, cx| { // let buffer_id = channel_buffer.read(cx).remote_id(cx); // let existing_view = pane // .items_of_type::() // .find(|view| view.read(cx).channel_buffer.read(cx).remote_id(cx) == buffer_id); // // If this channel buffer is already open in this pane, just return it. // if let Some(existing_view) = existing_view.clone() { // if existing_view.read(cx).channel_buffer == channel_buffer { // return existing_view; // } // } // let view = cx.add_view(|cx| { // let mut this = Self::new(project, channel_store, channel_buffer, cx); // this.acknowledge_buffer_version(cx); // this // }); // // If the pane contained a disconnected view for this channel buffer, // // replace that. // if let Some(existing_item) = existing_view { // if let Some(ix) = pane.index_for_item(&existing_item) { // pane.close_item_by_id(existing_item.id(), SaveIntent::Skip, cx) // .detach(); // pane.add_item(Box::new(view.clone()), true, true, Some(ix), cx); // } // } // view // }) // .ok_or_else(|| anyhow!("pane was dropped")) // }) // } // pub fn new( // project: ModelHandle, // channel_store: ModelHandle, // channel_buffer: ModelHandle, // cx: &mut ViewContext, // ) -> Self { // let buffer = channel_buffer.read(cx).buffer(); // let editor = cx.add_view(|cx| { // let mut editor = Editor::for_buffer(buffer, None, cx); // editor.set_collaboration_hub(Box::new(ChannelBufferCollaborationHub( // channel_buffer.clone(), // ))); // editor.set_read_only( // !channel_buffer // .read(cx) // .channel(cx) // .is_some_and(|c| c.can_edit_notes()), // ); // editor // }); // let _editor_event_subscription = cx.subscribe(&editor, |_, _, e, cx| cx.emit(e.clone())); // cx.subscribe(&channel_buffer, Self::handle_channel_buffer_event) // .detach(); // Self { // editor, // project, // channel_store, // channel_buffer, // remote_id: None, // _editor_event_subscription, // } // } // pub fn channel(&self, cx: &AppContext) -> Option> { // self.channel_buffer.read(cx).channel(cx) // } // fn handle_channel_buffer_event( // &mut self, // _: ModelHandle, // event: &ChannelBufferEvent, // cx: &mut ViewContext, // ) { // match event { // ChannelBufferEvent::Disconnected => self.editor.update(cx, |editor, cx| { // editor.set_read_only(true); // cx.notify(); // }), // ChannelBufferEvent::ChannelChanged => { // self.editor.update(cx, |editor, cx| { // editor.set_read_only(!self.channel(cx).is_some_and(|c| c.can_edit_notes())); // cx.emit(editor::Event::TitleChanged); // cx.notify() // }); // } // ChannelBufferEvent::BufferEdited => { // if cx.is_self_focused() || self.editor.is_focused(cx) { // self.acknowledge_buffer_version(cx); // } else { // self.channel_store.update(cx, |store, cx| { // let channel_buffer = self.channel_buffer.read(cx); // store.notes_changed( // channel_buffer.channel_id, // channel_buffer.epoch(), // &channel_buffer.buffer().read(cx).version(), // cx, // ) // }); // } // } // ChannelBufferEvent::CollaboratorsChanged => {} // } // } // fn acknowledge_buffer_version(&mut self, cx: &mut ViewContext<'_, '_, ChannelView>) { // self.channel_store.update(cx, |store, cx| { // let channel_buffer = self.channel_buffer.read(cx); // store.acknowledge_notes_version( // channel_buffer.channel_id, // channel_buffer.epoch(), // &channel_buffer.buffer().read(cx).version(), // cx, // ) // }); // self.channel_buffer.update(cx, |buffer, cx| { // buffer.acknowledge_buffer_version(cx); // }); // } // } // impl Entity for ChannelView { // type Event = editor::Event; // } // impl View for ChannelView { // fn ui_name() -> &'static str { // "ChannelView" // } // fn render(&mut self, cx: &mut ViewContext) -> AnyElement { // ChildView::new(self.editor.as_any(), cx).into_any() // } // fn focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext) { // if cx.is_self_focused() { // self.acknowledge_buffer_version(cx); // cx.focus(self.editor.as_any()) // } // } // } // impl Item for ChannelView { // fn act_as_type<'a>( // &'a self, // type_id: TypeId, // self_handle: &'a ViewHandle, // _: &'a AppContext, // ) -> Option<&'a AnyViewHandle> { // if type_id == TypeId::of::() { // Some(self_handle) // } else if type_id == TypeId::of::() { // Some(&self.editor) // } else { // None // } // } // fn tab_content( // &self, // _: Option, // style: &theme::Tab, // cx: &gpui::AppContext, // ) -> AnyElement { // let label = if let Some(channel) = self.channel(cx) { // match ( // channel.can_edit_notes(), // self.channel_buffer.read(cx).is_connected(), // ) { // (true, true) => format!("#{}", channel.name), // (false, true) => format!("#{} (read-only)", channel.name), // (_, false) => format!("#{} (disconnected)", channel.name), // } // } else { // format!("channel notes (disconnected)") // }; // Label::new(label, style.label.to_owned()).into_any() // } // fn clone_on_split(&self, _: WorkspaceId, cx: &mut ViewContext) -> Option { // Some(Self::new( // self.project.clone(), // self.channel_store.clone(), // self.channel_buffer.clone(), // cx, // )) // } // fn is_singleton(&self, _cx: &AppContext) -> bool { // false // } // fn navigate(&mut self, data: Box, cx: &mut ViewContext) -> bool { // self.editor // .update(cx, |editor, cx| editor.navigate(data, cx)) // } // fn deactivated(&mut self, cx: &mut ViewContext) { // self.editor // .update(cx, |editor, cx| Item::deactivated(editor, cx)) // } // fn set_nav_history(&mut self, history: ItemNavHistory, cx: &mut ViewContext) { // self.editor // .update(cx, |editor, cx| Item::set_nav_history(editor, history, cx)) // } // fn as_searchable(&self, _: &ViewHandle) -> Option> { // Some(Box::new(self.editor.clone())) // } // fn show_toolbar(&self) -> bool { // true // } // fn pixel_position_of_cursor(&self, cx: &AppContext) -> Option { // self.editor.read(cx).pixel_position_of_cursor(cx) // } // fn to_item_events(event: &Self::Event) -> SmallVec<[ItemEvent; 2]> { // editor::Editor::to_item_events(event) // } // } // impl FollowableItem for ChannelView { // fn remote_id(&self) -> Option { // self.remote_id // } // fn to_state_proto(&self, cx: &AppContext) -> Option { // let channel_buffer = self.channel_buffer.read(cx); // if !channel_buffer.is_connected() { // return None; // } // Some(proto::view::Variant::ChannelView( // proto::view::ChannelView { // channel_id: channel_buffer.channel_id, // editor: if let Some(proto::view::Variant::Editor(proto)) = // self.editor.read(cx).to_state_proto(cx) // { // Some(proto) // } else { // None // }, // }, // )) // } // fn from_state_proto( // pane: ViewHandle, // workspace: ViewHandle, // remote_id: workspace::ViewId, // state: &mut Option, // cx: &mut AppContext, // ) -> Option>>> { // let Some(proto::view::Variant::ChannelView(_)) = state else { // return None; // }; // let Some(proto::view::Variant::ChannelView(state)) = state.take() else { // unreachable!() // }; // let open = ChannelView::open_in_pane(state.channel_id, pane, workspace, cx); // Some(cx.spawn(|mut cx| async move { // let this = open.await?; // let task = this // .update(&mut cx, |this, cx| { // this.remote_id = Some(remote_id); // if let Some(state) = state.editor { // Some(this.editor.update(cx, |editor, cx| { // editor.apply_update_proto( // &this.project, // proto::update_view::Variant::Editor(proto::update_view::Editor { // selections: state.selections, // pending_selection: state.pending_selection, // scroll_top_anchor: state.scroll_top_anchor, // scroll_x: state.scroll_x, // scroll_y: state.scroll_y, // ..Default::default() // }), // cx, // ) // })) // } else { // None // } // }) // .ok_or_else(|| anyhow!("window was closed"))?; // if let Some(task) = task { // task.await?; // } // Ok(this) // })) // } // fn add_event_to_update_proto( // &self, // event: &Self::Event, // update: &mut Option, // cx: &AppContext, // ) -> bool { // self.editor // .read(cx) // .add_event_to_update_proto(event, update, cx) // } // fn apply_update_proto( // &mut self, // project: &ModelHandle, // message: proto::update_view::Variant, // cx: &mut ViewContext, // ) -> gpui::Task> { // self.editor.update(cx, |editor, cx| { // editor.apply_update_proto(project, message, cx) // }) // } // fn set_leader_peer_id(&mut self, leader_peer_id: Option, cx: &mut ViewContext) { // self.editor.update(cx, |editor, cx| { // editor.set_leader_peer_id(leader_peer_id, cx) // }) // } // fn should_unfollow_on_event(event: &Self::Event, cx: &AppContext) -> bool { // Editor::should_unfollow_on_event(event, cx) // } // fn is_project_item(&self, _cx: &AppContext) -> bool { // false // } // } // struct ChannelBufferCollaborationHub(ModelHandle); // impl CollaborationHub for ChannelBufferCollaborationHub { // fn collaborators<'a>(&self, cx: &'a AppContext) -> &'a HashMap { // self.0.read(cx).collaborators() // } // fn user_participant_indices<'a>( // &self, // cx: &'a AppContext, // ) -> &'a HashMap { // self.0.read(cx).user_store().read(cx).participant_indices() // } // }