diff --git a/gpui/src/elements/list.rs b/gpui/src/elements/list.rs index 467f53fd4fdd64dbe74060a3682250eb4e696e2c..d6101a59512b1f256f2e6f6438a77a286929e33c 100644 --- a/gpui/src/elements/list.rs +++ b/gpui/src/elements/list.rs @@ -106,6 +106,7 @@ impl Element for List { } fn paint(&mut self, bounds: RectF, _: &mut (), cx: &mut PaintContext) { + cx.scene.push_layer(Some(bounds)); let state = &mut *self.state.0.lock(); let visible_range = state.visible_range(bounds.height()); @@ -119,6 +120,7 @@ impl Element for List { element.paint(origin, cx); item_top += element.size().y(); } + cx.scene.pop_layer(); } fn dispatch_event( diff --git a/server/src/rpc.rs b/server/src/rpc.rs index 5b907df01ec9337684723bb82e83b9d76e3c32d0..f489bfb57debddc255eee2e9da06cde6f011c264 100644 --- a/server/src/rpc.rs +++ b/server/src/rpc.rs @@ -1425,12 +1425,13 @@ mod tests { .await .unwrap(); - let channels_a = ChannelList::new(client_a, &mut cx_a.to_async()) - .await - .unwrap(); + let channels_a = cx_a.add_model(|cx| ChannelList::new(client_a, cx)); + channels_a + .condition(&mut cx_a, |list, _| list.available_channels().is_some()) + .await; channels_a.read_with(&cx_a, |list, _| { assert_eq!( - list.available_channels(), + list.available_channels().unwrap(), &[ChannelDetails { id: channel_id.to_proto(), name: "test-channel".to_string() @@ -1448,12 +1449,13 @@ mod tests { }) .await; - let channels_b = ChannelList::new(client_b, &mut cx_b.to_async()) - .await - .unwrap(); + let channels_b = cx_b.add_model(|cx| ChannelList::new(client_b, cx)); + channels_b + .condition(&mut cx_b, |list, _| list.available_channels().is_some()) + .await; channels_b.read_with(&cx_b, |list, _| { assert_eq!( - list.available_channels(), + list.available_channels().unwrap(), &[ChannelDetails { id: channel_id.to_proto(), name: "test-channel".to_string() diff --git a/zed/src/channel.rs b/zed/src/channel.rs index fe683b728c035fa18d5cb071351f51cc17ef4baf..efb51eb239adededbbd65013cf9598530f26a0d0 100644 --- a/zed/src/channel.rs +++ b/zed/src/channel.rs @@ -3,9 +3,7 @@ use crate::{ util::log_async_errors, }; use anyhow::{anyhow, Context, Result}; -use gpui::{ - AsyncAppContext, Entity, ModelContext, ModelHandle, MutableAppContext, WeakModelHandle, -}; +use gpui::{Entity, ModelContext, ModelHandle, MutableAppContext, WeakModelHandle}; use std::{ cmp::Ordering, collections::{hash_map, BTreeSet, HashMap}, @@ -17,7 +15,7 @@ use zrpc::{ }; pub struct ChannelList { - available_channels: Vec, + available_channels: Option>, channels: HashMap>, rpc: Arc, } @@ -55,21 +53,32 @@ impl Entity for ChannelList { } impl ChannelList { - pub async fn new(rpc: Arc, cx: &mut AsyncAppContext) -> Result> { - let response = rpc - .request(proto::GetChannels {}) - .await - .context("failed to fetch available channels")?; - - Ok(cx.add_model(|_| Self { - available_channels: response.channels.into_iter().map(Into::into).collect(), + pub fn new(rpc: Arc, cx: &mut ModelContext) -> Self { + cx.spawn(|this, mut cx| { + let rpc = rpc.clone(); + log_async_errors(async move { + let response = rpc + .request(proto::GetChannels {}) + .await + .context("failed to fetch available channels")?; + this.update(&mut cx, |this, cx| { + this.available_channels = + Some(response.channels.into_iter().map(Into::into).collect()); + cx.notify(); + }); + Ok(()) + }) + }) + .detach(); + Self { + available_channels: None, channels: Default::default(), rpc, - })) + } } - pub fn available_channels(&self) -> &[ChannelDetails] { - &self.available_channels + pub fn available_channels(&self) -> Option<&[ChannelDetails]> { + self.available_channels.as_ref().map(Vec::as_slice) } pub fn get_channel( @@ -82,8 +91,8 @@ impl ChannelList { hash_map::Entry::Vacant(entry) => { if let Some(details) = self .available_channels - .iter() - .find(|details| details.id == id) + .as_ref() + .and_then(|channels| channels.iter().find(|details| details.id == id)) { let rpc = self.rpc.clone(); let channel = cx.add_model(|cx| Channel::new(details.clone(), rpc, cx)); diff --git a/zed/src/chat_panel.rs b/zed/src/chat_panel.rs index 3ef6ed904ae0cf94c8f7deb2032d0bbf1740d1d9..86a7762fac3b33146f078bf912fb25ee30a8d5d6 100644 --- a/zed/src/chat_panel.rs +++ b/zed/src/chat_panel.rs @@ -1,38 +1,48 @@ -use crate::Settings; - -use super::channel::{Channel, ChannelList}; +use super::{ + channel::{Channel, ChannelList}, + Settings, +}; use gpui::{elements::*, Entity, ModelHandle, RenderContext, View, ViewContext}; use postage::watch; pub struct ChatPanel { - // channel_list: ModelHandle, - // active_channel: Option>, + channel_list: ModelHandle, + active_channel: Option>, + // active_channel_subscription: Subscription, messages: ListState, } pub enum Event {} impl ChatPanel { - pub fn new(settings: watch::Receiver) -> Self { - let settings = settings.borrow(); - let mut messages = Vec::new(); - for i in 0..1000 { - messages.push( - Container::new( - Label::new( - format!("This is message {}", i), - settings.ui_font_family, - settings.ui_font_size, - ) - .with_style(&settings.theme.selector.label) - .boxed(), - ) - .boxed(), - ); - } - Self { - messages: ListState::new(messages), + pub fn new( + channel_list: ModelHandle, + settings: watch::Receiver, + cx: &mut ViewContext, + ) -> Self { + let mut this = Self { + channel_list, + messages: ListState::new(Vec::new()), + active_channel: None, + }; + let channel = this.channel_list.update(cx, |list, cx| { + if let Some(channel_id) = list + .available_channels() + .and_then(|channels| channels.first()) + .map(|details| details.id) + { + return list.get_channel(channel_id, cx); + } + None + }); + if let Some(channel) = channel { + this.set_active_channel(channel); } + this + } + + pub fn set_active_channel(&mut self, channel: ModelHandle) { + // } } diff --git a/zed/src/editor.rs b/zed/src/editor.rs index 829233b3cf74a19d4579a2ba9dfadf283ba1c7de..49259f554cb6a140dce5d71a0103a3f2f891de37 100644 --- a/zed/src/editor.rs +++ b/zed/src/editor.rs @@ -2596,8 +2596,9 @@ mod tests { use super::*; use crate::{ editor::Point, + language::LanguageRegistry, settings, - test::{build_app_state, sample_text}, + test::{build_settings, sample_text}, }; use buffer::History; use unindent::Unindent; @@ -4120,8 +4121,9 @@ mod tests { #[gpui::test] async fn test_select_larger_smaller_syntax_node(mut cx: gpui::TestAppContext) { - let app_state = cx.read(build_app_state); - let lang = app_state.languages.select_language("z.rs"); + let settings = cx.read(build_settings); + let languages = LanguageRegistry::new(); + let lang = languages.select_language("z.rs"); let text = r#" use mod1::mod2::{mod3, mod4}; @@ -4134,8 +4136,7 @@ mod tests { let history = History::new(text.into()); Buffer::from_history(0, history, None, lang.cloned(), cx) }); - let (_, view) = - cx.add_window(|cx| Editor::for_buffer(buffer, app_state.settings.clone(), cx)); + let (_, view) = cx.add_window(|cx| Editor::for_buffer(buffer, settings.clone(), cx)); view.condition(&cx, |view, cx| !view.buffer.read(cx).is_parsing()) .await; diff --git a/zed/src/editor/buffer.rs b/zed/src/editor/buffer.rs index 624c84697aebab163a5457f87a8d247f64a4997d..07ea5bacdc243c78ac4e9fe29f95814a40efab7c 100644 --- a/zed/src/editor/buffer.rs +++ b/zed/src/editor/buffer.rs @@ -2641,7 +2641,7 @@ impl<'a> Into for &'a Operation { }, ), #[cfg(test)] - Operation::Test(_) => unimplemented!() + Operation::Test(_) => unimplemented!(), }), } } @@ -2895,7 +2895,8 @@ mod tests { use super::*; use crate::{ fs::RealFs, - test::{build_app_state, temp_tree}, + language::LanguageRegistry, + test::temp_tree, util::RandomCharIter, worktree::{Worktree, WorktreeHandle as _}, }; @@ -3825,8 +3826,8 @@ mod tests { #[gpui::test] async fn test_reparse(mut cx: gpui::TestAppContext) { - let app_state = cx.read(build_app_state); - let rust_lang = app_state.languages.select_language("test.rs"); + let languages = LanguageRegistry::new(); + let rust_lang = languages.select_language("test.rs"); assert!(rust_lang.is_some()); let buffer = cx.add_model(|cx| { @@ -3966,8 +3967,8 @@ mod tests { async fn test_enclosing_bracket_ranges(mut cx: gpui::TestAppContext) { use unindent::Unindent as _; - let app_state = cx.read(build_app_state); - let rust_lang = app_state.languages.select_language("test.rs"); + let languages = LanguageRegistry::new(); + let rust_lang = languages.select_language("test.rs"); assert!(rust_lang.is_some()); let buffer = cx.add_model(|cx| { diff --git a/zed/src/file_finder.rs b/zed/src/file_finder.rs index 4d4cf13013d3fcc89fc5bc4a16cd658bee186ea4..50bddb37171e7c793f6cc26aa63443c96a0cdb2b 100644 --- a/zed/src/file_finder.rs +++ b/zed/src/file_finder.rs @@ -455,7 +455,7 @@ mod tests { editor::init(cx); }); - let app_state = cx.read(build_app_state); + let app_state = cx.update(build_app_state); let (window_id, workspace) = cx.add_window(|cx| Workspace::new(&app_state, cx)); workspace .update(&mut cx, |workspace, cx| { @@ -515,7 +515,7 @@ mod tests { ) .await; - let mut app_state = cx.read(build_app_state); + let mut app_state = cx.update(build_app_state); Arc::get_mut(&mut app_state).unwrap().fs = fs; let (_, workspace) = cx.add_window(|cx| Workspace::new(&app_state, cx)); @@ -577,7 +577,7 @@ mod tests { fs::create_dir(&dir_path).unwrap(); fs::write(&file_path, "").unwrap(); - let app_state = cx.read(build_app_state); + let app_state = cx.update(build_app_state); let (_, workspace) = cx.add_window(|cx| Workspace::new(&app_state, cx)); workspace .update(&mut cx, |workspace, cx| { @@ -624,7 +624,7 @@ mod tests { "dir2": { "a.txt": "" } })); - let app_state = cx.read(build_app_state); + let app_state = cx.update(build_app_state); let (_, workspace) = cx.add_window(|cx| Workspace::new(&app_state, cx)); workspace diff --git a/zed/src/lib.rs b/zed/src/lib.rs index d76a308e386d9dc8f133d805d91777e69ad0e94d..2290d5cf28aa476a65658ea35665a6d67fcd4483 100644 --- a/zed/src/lib.rs +++ b/zed/src/lib.rs @@ -19,7 +19,8 @@ mod util; pub mod workspace; pub mod worktree; -use gpui::action; +use channel::ChannelList; +use gpui::{action, ModelHandle}; pub use settings::Settings; use parking_lot::Mutex; @@ -36,6 +37,7 @@ pub struct AppState { pub themes: Arc, pub rpc: Arc, pub fs: Arc, + pub channel_list: ModelHandle, } pub fn init(cx: &mut gpui::MutableAppContext) { diff --git a/zed/src/main.rs b/zed/src/main.rs index c35b2bf91507f7723e6f8ea40d3973e3c3d5183a..e3e365d15e888d70983c19cb0eae4917bfd2e5eb 100644 --- a/zed/src/main.rs +++ b/zed/src/main.rs @@ -7,7 +7,9 @@ use parking_lot::Mutex; use simplelog::SimpleLogger; use std::{fs, path::PathBuf, sync::Arc}; use zed::{ - self, assets, editor, file_finder, + self, assets, + channel::ChannelList, + editor, file_finder, fs::RealFs, language, menus, rpc, settings, theme_selector, workspace::{self, OpenParams, OpenPaths}, @@ -25,17 +27,17 @@ fn main() { let languages = Arc::new(language::LanguageRegistry::new()); languages.set_theme(&settings.borrow().theme); - let app_state = AppState { - languages: languages.clone(), - settings_tx: Arc::new(Mutex::new(settings_tx)), - settings, - themes, - rpc: rpc::Client::new(), - fs: Arc::new(RealFs), - }; - app.run(move |cx| { - let app_state = Arc::new(app_state); + let rpc = rpc::Client::new(); + let app_state = Arc::new(AppState { + languages: languages.clone(), + settings_tx: Arc::new(Mutex::new(settings_tx)), + settings, + themes, + channel_list: cx.add_model(|cx| ChannelList::new(rpc.clone(), cx)), + rpc, + fs: Arc::new(RealFs), + }); zed::init(cx); workspace::init(cx); diff --git a/zed/src/test.rs b/zed/src/test.rs index 6c861a31e5c846be04f2a79ac5e6315d4f420563..9263e0750f3e34cdef236f9d3f43c6aecba76d0e 100644 --- a/zed/src/test.rs +++ b/zed/src/test.rs @@ -1,13 +1,15 @@ use crate::{ + channel::ChannelList, fs::RealFs, language::LanguageRegistry, rpc, settings::{self, ThemeRegistry}, time::ReplicaId, - AppState, + AppState, Settings, }; -use gpui::{AppContext, Entity, ModelHandle}; +use gpui::{AppContext, Entity, ModelHandle, MutableAppContext}; use parking_lot::Mutex; +use postage::watch; use smol::channel; use std::{ marker::PhantomData, @@ -153,16 +155,22 @@ fn write_tree(path: &Path, tree: serde_json::Value) { } } -pub fn build_app_state(cx: &AppContext) -> Arc { +pub fn build_settings(cx: &AppContext) -> watch::Receiver { + settings::channel(&cx.font_cache()).unwrap().1 +} + +pub fn build_app_state(cx: &mut MutableAppContext) -> Arc { let (settings_tx, settings) = settings::channel(&cx.font_cache()).unwrap(); let languages = Arc::new(LanguageRegistry::new()); let themes = ThemeRegistry::new(()); + let rpc = rpc::Client::new(); Arc::new(AppState { settings_tx: Arc::new(Mutex::new(settings_tx)), settings, themes, languages: languages.clone(), - rpc: rpc::Client::new(), + channel_list: cx.add_model(|cx| ChannelList::new(rpc.clone(), cx)), + rpc, fs: Arc::new(RealFs), }) } diff --git a/zed/src/workspace.rs b/zed/src/workspace.rs index 69baa2283d1d31249a44e68c531f7c48ef1c84ad..0dffa81be921798113a5c7f49a2ec1faedda2ae0 100644 --- a/zed/src/workspace.rs +++ b/zed/src/workspace.rs @@ -372,8 +372,14 @@ impl Workspace { let mut right_sidebar = Sidebar::new(Side::Right); right_sidebar.add_item( "icons/comment-16.svg", - cx.add_view(|_| ChatPanel::new(app_state.settings.clone())) - .into(), + cx.add_view(|cx| { + ChatPanel::new( + app_state.channel_list.clone(), + app_state.settings.clone(), + cx, + ) + }) + .into(), ); right_sidebar.add_item("icons/user-16.svg", cx.add_view(|_| ProjectBrowser).into()); @@ -1018,7 +1024,7 @@ mod tests { #[gpui::test] async fn test_open_paths_action(mut cx: gpui::TestAppContext) { - let app_state = cx.read(build_app_state); + let app_state = cx.update(build_app_state); let dir = temp_tree(json!({ "a": { "aa": null, @@ -1091,7 +1097,7 @@ mod tests { }, })); - let app_state = cx.read(build_app_state); + let app_state = cx.update(build_app_state); let (_, workspace) = cx.add_window(|cx| Workspace::new(&app_state, cx)); workspace @@ -1195,7 +1201,7 @@ mod tests { fs.insert_file("/dir1/a.txt", "".into()).await.unwrap(); fs.insert_file("/dir2/b.txt", "".into()).await.unwrap(); - let mut app_state = cx.read(build_app_state); + let mut app_state = cx.update(build_app_state); Arc::get_mut(&mut app_state).unwrap().fs = Arc::new(fs); let (_, workspace) = cx.add_window(|cx| Workspace::new(&app_state, cx)); @@ -1264,7 +1270,7 @@ mod tests { "a.txt": "", })); - let app_state = cx.read(build_app_state); + let app_state = cx.update(build_app_state); let (window_id, workspace) = cx.add_window(|cx| Workspace::new(&app_state, cx)); workspace .update(&mut cx, |workspace, cx| { @@ -1309,7 +1315,7 @@ mod tests { #[gpui::test] async fn test_open_and_save_new_file(mut cx: gpui::TestAppContext) { let dir = TempDir::new("test-new-file").unwrap(); - let app_state = cx.read(build_app_state); + let app_state = cx.update(build_app_state); let (_, workspace) = cx.add_window(|cx| Workspace::new(&app_state, cx)); workspace .update(&mut cx, |workspace, cx| { @@ -1408,7 +1414,7 @@ mod tests { async fn test_new_empty_workspace(mut cx: gpui::TestAppContext) { cx.update(init); - let app_state = cx.read(build_app_state); + let app_state = cx.update(build_app_state); cx.dispatch_global_action(OpenNew(app_state)); let window_id = *cx.window_ids().first().unwrap(); let workspace = cx.root_view::(window_id).unwrap(); @@ -1454,7 +1460,7 @@ mod tests { }, })); - let app_state = cx.read(build_app_state); + let app_state = cx.update(build_app_state); let (window_id, workspace) = cx.add_window(|cx| Workspace::new(&app_state, cx)); workspace .update(&mut cx, |workspace, cx| { diff --git a/zed/src/worktree.rs b/zed/src/worktree.rs index 6c7ba34a15914e3bc75c3b44fc7220e73e928b46..e121bc5d14e3b2b9469619af0af34f7e38c9ae4c 100644 --- a/zed/src/worktree.rs +++ b/zed/src/worktree.rs @@ -2640,13 +2640,12 @@ mod tests { #[gpui::test] async fn test_save_file(mut cx: gpui::TestAppContext) { - let app_state = cx.read(build_app_state); let dir = temp_tree(json!({ "file1": "the old contents", })); let tree = Worktree::open_local( dir.path(), - app_state.languages.clone(), + Arc::new(LanguageRegistry::new()), Arc::new(RealFs), &mut cx.to_async(), ) @@ -2668,7 +2667,6 @@ mod tests { #[gpui::test] async fn test_save_in_single_file_worktree(mut cx: gpui::TestAppContext) { - let app_state = cx.read(build_app_state); let dir = temp_tree(json!({ "file1": "the old contents", })); @@ -2676,7 +2674,7 @@ mod tests { let tree = Worktree::open_local( file_path.clone(), - app_state.languages.clone(), + Arc::new(LanguageRegistry::new()), Arc::new(RealFs), &mut cx.to_async(), )