Add ChannelList to AppState

This commit is contained in:
Max Brunsfeld 2021-08-23 15:02:42 -07:00
parent 43bb38206f
commit 5ecedd894d
12 changed files with 134 additions and 93 deletions

View File

@ -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(

View File

@ -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()

View File

@ -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));

View File

@ -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>) {
//
}
}

View File

@ -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;

View File

@ -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| {

View File

@ -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

View File

@ -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) {

View File

@ -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);

View File

@ -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),
})
}

View File

@ -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| {

View File

@ -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(),
)