Detailed changes
@@ -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(
@@ -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()
@@ -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<ChannelDetails>,
+ available_channels: Option<Vec<ChannelDetails>>,
channels: HashMap<u64, WeakModelHandle<Channel>>,
rpc: Arc<Client>,
}
@@ -55,21 +53,32 @@ impl Entity for ChannelList {
}
impl ChannelList {
- pub async fn new(rpc: Arc<rpc::Client>, cx: &mut AsyncAppContext) -> Result<ModelHandle<Self>> {
- 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<rpc::Client>, cx: &mut ModelContext<Self>) -> 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));
@@ -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<ChannelList>,
- // active_channel: Option<ModelHandle<Channel>>,
+ channel_list: ModelHandle<ChannelList>,
+ active_channel: Option<ModelHandle<Channel>>,
+ // active_channel_subscription: Subscription,
messages: ListState,
}
pub enum Event {}
impl ChatPanel {
- pub fn new(settings: watch::Receiver<Settings>) -> 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<ChannelList>,
+ settings: watch::Receiver<Settings>,
+ cx: &mut ViewContext<Self>,
+ ) -> 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<Channel>) {
+ //
}
}
@@ -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;
@@ -2641,7 +2641,7 @@ impl<'a> Into<proto::Operation> 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| {
@@ -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
@@ -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<settings::ThemeRegistry>,
pub rpc: Arc<rpc::Client>,
pub fs: Arc<dyn fs::Fs>,
+ pub channel_list: ModelHandle<ChannelList>,
}
pub fn init(cx: &mut gpui::MutableAppContext) {
@@ -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);
@@ -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<AppState> {
+pub fn build_settings(cx: &AppContext) -> watch::Receiver<Settings> {
+ settings::channel(&cx.font_cache()).unwrap().1
+}
+
+pub fn build_app_state(cx: &mut MutableAppContext) -> Arc<AppState> {
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),
})
}
@@ -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::<Workspace>(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| {
@@ -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(),
)