This commit is contained in:
Max Brunsfeld 2023-11-01 11:59:49 -07:00 committed by Nathan Sobo
parent 57ffa8201e
commit dd1a2a9e44
16 changed files with 138 additions and 181 deletions

View file

@ -8,10 +8,9 @@ pub enum ProviderCredential {
NotNeeded, NotNeeded,
} }
#[async_trait] pub trait CredentialProvider {
pub trait CredentialProvider: Send + Sync {
fn has_credentials(&self) -> bool; fn has_credentials(&self) -> bool;
async fn retrieve_credentials(&self, cx: &mut AppContext) -> ProviderCredential; fn retrieve_credentials(&self, cx: &mut AppContext) -> ProviderCredential;
async fn save_credentials(&self, cx: &mut AppContext, credential: ProviderCredential); fn save_credentials(&self, cx: &mut AppContext, credential: ProviderCredential);
async fn delete_credentials(&self, cx: &mut AppContext); fn delete_credentials(&self, cx: &mut AppContext);
} }

View file

@ -213,7 +213,6 @@ impl OpenAICompletionProvider {
} }
} }
#[async_trait]
impl CredentialProvider for OpenAICompletionProvider { impl CredentialProvider for OpenAICompletionProvider {
fn has_credentials(&self) -> bool { fn has_credentials(&self) -> bool {
match *self.credential.read() { match *self.credential.read() {
@ -221,50 +220,44 @@ impl CredentialProvider for OpenAICompletionProvider {
_ => false, _ => false,
} }
} }
async fn retrieve_credentials(&self, cx: &mut AppContext) -> ProviderCredential {
fn retrieve_credentials(&self, cx: &mut AppContext) -> ProviderCredential {
let existing_credential = self.credential.read().clone(); let existing_credential = self.credential.read().clone();
let retrieved_credential = match existing_credential {
let retrieved_credential = cx ProviderCredential::Credentials { .. } => existing_credential.clone(),
.run_on_main(move |cx| match existing_credential { _ => {
ProviderCredential::Credentials { .. } => { if let Some(api_key) = env::var("OPENAI_API_KEY").log_err() {
return existing_credential.clone(); ProviderCredential::Credentials { api_key }
} } else if let Some(Some((_, api_key))) =
_ => { cx.read_credentials(OPENAI_API_URL).log_err()
if let Some(api_key) = env::var("OPENAI_API_KEY").log_err() { {
return ProviderCredential::Credentials { api_key }; if let Some(api_key) = String::from_utf8(api_key).log_err() {
} ProviderCredential::Credentials { api_key }
if let Some(Some((_, api_key))) = cx.read_credentials(OPENAI_API_URL).log_err()
{
if let Some(api_key) = String::from_utf8(api_key).log_err() {
return ProviderCredential::Credentials { api_key };
} else {
return ProviderCredential::NoCredentials;
}
} else { } else {
return ProviderCredential::NoCredentials; ProviderCredential::NoCredentials
} }
} else {
ProviderCredential::NoCredentials
} }
}) }
.await; };
*self.credential.write() = retrieved_credential.clone(); *self.credential.write() = retrieved_credential.clone();
retrieved_credential retrieved_credential
} }
async fn save_credentials(&self, cx: &mut AppContext, credential: ProviderCredential) { fn save_credentials(&self, cx: &mut AppContext, credential: ProviderCredential) {
*self.credential.write() = credential.clone(); *self.credential.write() = credential.clone();
let credential = credential.clone(); let credential = credential.clone();
cx.run_on_main(move |cx| match credential { match credential {
ProviderCredential::Credentials { api_key } => { ProviderCredential::Credentials { api_key } => {
cx.write_credentials(OPENAI_API_URL, "Bearer", api_key.as_bytes()) cx.write_credentials(OPENAI_API_URL, "Bearer", api_key.as_bytes())
.log_err(); .log_err();
} }
_ => {} _ => {}
}) }
.await;
} }
async fn delete_credentials(&self, cx: &mut AppContext) {
fn delete_credentials(&self, cx: &mut AppContext) {
cx.run_on_main(move |cx| cx.delete_credentials(OPENAI_API_URL).log_err()) cx.run_on_main(move |cx| cx.delete_credentials(OPENAI_API_URL).log_err())
.await; .await;
*self.credential.write() = ProviderCredential::NoCredentials; *self.credential.write() = ProviderCredential::NoCredentials;

View file

@ -1,14 +1,13 @@
use assets::SoundRegistry; use assets::SoundRegistry;
use futures::{channel::mpsc, StreamExt}; use gpui2::{AppContext, AssetSource};
use gpui2::{AppContext, AssetSource, BackgroundExecutor};
use rodio::{OutputStream, OutputStreamHandle}; use rodio::{OutputStream, OutputStreamHandle};
use util::ResultExt; use util::ResultExt;
mod assets; mod assets;
pub fn init(source: impl AssetSource, cx: &mut AppContext) { pub fn init(source: impl AssetSource, cx: &mut AppContext) {
cx.set_global(Audio::new(cx.executor()));
cx.set_global(SoundRegistry::new(source)); cx.set_global(SoundRegistry::new(source));
cx.set_global(Audio::new());
} }
pub enum Sound { pub enum Sound {
@ -34,15 +33,18 @@ impl Sound {
} }
pub struct Audio { pub struct Audio {
tx: mpsc::UnboundedSender<Box<dyn FnOnce(&mut AudioState)>>,
}
struct AudioState {
_output_stream: Option<OutputStream>, _output_stream: Option<OutputStream>,
output_handle: Option<OutputStreamHandle>, output_handle: Option<OutputStreamHandle>,
} }
impl AudioState { impl Audio {
pub fn new() -> Self {
Self {
_output_stream: None,
output_handle: None,
}
}
fn ensure_output_exists(&mut self) -> Option<&OutputStreamHandle> { fn ensure_output_exists(&mut self) -> Option<&OutputStreamHandle> {
if self.output_handle.is_none() { if self.output_handle.is_none() {
let (_output_stream, output_handle) = OutputStream::try_default().log_err().unzip(); let (_output_stream, output_handle) = OutputStream::try_default().log_err().unzip();
@ -53,59 +55,27 @@ impl AudioState {
self.output_handle.as_ref() self.output_handle.as_ref()
} }
fn take(&mut self) {
self._output_stream.take();
self.output_handle.take();
}
}
impl Audio {
pub fn new(executor: &BackgroundExecutor) -> Self {
let (tx, mut rx) = mpsc::unbounded::<Box<dyn FnOnce(&mut AudioState)>>();
executor
.spawn_on_main(|| async move {
let mut audio = AudioState {
_output_stream: None,
output_handle: None,
};
while let Some(f) = rx.next().await {
(f)(&mut audio);
}
})
.detach();
Self { tx }
}
pub fn play_sound(sound: Sound, cx: &mut AppContext) { pub fn play_sound(sound: Sound, cx: &mut AppContext) {
if !cx.has_global::<Self>() { if !cx.has_global::<Self>() {
return; return;
} }
let Some(source) = SoundRegistry::global(cx).get(sound.file()).log_err() else { cx.update_global::<Self, _>(|this, cx| {
return; let output_handle = this.ensure_output_exists()?;
}; let source = SoundRegistry::global(cx).get(sound.file()).log_err()?;
output_handle.play_raw(source).log_err()?;
let this = cx.global::<Self>(); Some(())
this.tx });
.unbounded_send(Box::new(move |state| {
if let Some(output_handle) = state.ensure_output_exists() {
output_handle.play_raw(source).log_err();
}
}))
.ok();
} }
pub fn end_call(cx: &AppContext) { pub fn end_call(cx: &mut AppContext) {
if !cx.has_global::<Self>() { if !cx.has_global::<Self>() {
return; return;
} }
let this = cx.global::<Self>(); cx.update_global::<Self, _>(|this, _| {
this._output_stream.take();
this.tx this.output_handle.take();
.unbounded_send(Box::new(move |state| state.take())) });
.ok();
} }
} }

View file

@ -11,7 +11,8 @@ use async_tungstenite::tungstenite::{
http::{Request, StatusCode}, http::{Request, StatusCode},
}; };
use futures::{ use futures::{
future::BoxFuture, AsyncReadExt, FutureExt, SinkExt, StreamExt, TryFutureExt as _, TryStreamExt, future::LocalBoxFuture, AsyncReadExt, FutureExt, SinkExt, StreamExt, TryFutureExt as _,
TryStreamExt,
}; };
use gpui2::{ use gpui2::{
serde_json, AnyModel, AnyWeakModel, AppContext, AsyncAppContext, Model, SemanticVersion, Task, serde_json, AnyModel, AnyWeakModel, AppContext, AsyncAppContext, Model, SemanticVersion, Task,
@ -233,14 +234,12 @@ struct ClientState {
message_handlers: HashMap< message_handlers: HashMap<
TypeId, TypeId,
Arc< Arc<
dyn Send dyn Fn(
+ Sync AnyModel,
+ Fn( Box<dyn AnyTypedEnvelope>,
AnyModel, &Arc<Client>,
Box<dyn AnyTypedEnvelope>, AsyncAppContext,
&Arc<Client>, ) -> LocalBoxFuture<'static, Result<()>>,
AsyncAppContext,
) -> BoxFuture<'static, Result<()>>,
>, >,
>, >,
} }
@ -310,10 +309,7 @@ pub struct PendingEntitySubscription<T: 'static> {
consumed: bool, consumed: bool,
} }
impl<T> PendingEntitySubscription<T> impl<T: 'static> PendingEntitySubscription<T> {
where
T: 'static + Send,
{
pub fn set_model(mut self, model: &Model<T>, cx: &mut AsyncAppContext) -> Subscription { pub fn set_model(mut self, model: &Model<T>, cx: &mut AsyncAppContext) -> Subscription {
self.consumed = true; self.consumed = true;
let mut state = self.client.state.write(); let mut state = self.client.state.write();
@ -341,10 +337,7 @@ where
} }
} }
impl<T> Drop for PendingEntitySubscription<T> impl<T: 'static> Drop for PendingEntitySubscription<T> {
where
T: 'static,
{
fn drop(&mut self) { fn drop(&mut self) {
if !self.consumed { if !self.consumed {
let mut state = self.client.state.write(); let mut state = self.client.state.write();
@ -529,7 +522,7 @@ impl Client {
remote_id: u64, remote_id: u64,
) -> Result<PendingEntitySubscription<T>> ) -> Result<PendingEntitySubscription<T>>
where where
T: 'static + Send, T: 'static,
{ {
let id = (TypeId::of::<T>(), remote_id); let id = (TypeId::of::<T>(), remote_id);
@ -557,9 +550,9 @@ impl Client {
) -> Subscription ) -> Subscription
where where
M: EnvelopedMessage, M: EnvelopedMessage,
E: 'static + Send, E: 'static,
H: 'static + Send + Sync + Fn(Model<E>, TypedEnvelope<M>, Arc<Self>, AsyncAppContext) -> F, H: 'static + Sync + Fn(Model<E>, TypedEnvelope<M>, Arc<Self>, AsyncAppContext) -> F,
F: 'static + Future<Output = Result<()>> + Send, F: 'static + Future<Output = Result<()>>,
{ {
let message_type_id = TypeId::of::<M>(); let message_type_id = TypeId::of::<M>();
@ -573,7 +566,7 @@ impl Client {
Arc::new(move |subscriber, envelope, client, cx| { Arc::new(move |subscriber, envelope, client, cx| {
let subscriber = subscriber.downcast::<E>().unwrap(); let subscriber = subscriber.downcast::<E>().unwrap();
let envelope = envelope.into_any().downcast::<TypedEnvelope<M>>().unwrap(); let envelope = envelope.into_any().downcast::<TypedEnvelope<M>>().unwrap();
handler(subscriber, *envelope, client.clone(), cx).boxed() handler(subscriber, *envelope, client.clone(), cx).boxed_local()
}), }),
); );
if prev_handler.is_some() { if prev_handler.is_some() {
@ -599,9 +592,9 @@ impl Client {
) -> Subscription ) -> Subscription
where where
M: RequestMessage, M: RequestMessage,
E: 'static + Send, E: 'static,
H: 'static + Send + Sync + Fn(Model<E>, TypedEnvelope<M>, Arc<Self>, AsyncAppContext) -> F, H: 'static + Sync + Fn(Model<E>, TypedEnvelope<M>, Arc<Self>, AsyncAppContext) -> F,
F: 'static + Future<Output = Result<M::Response>> + Send, F: 'static + Future<Output = Result<M::Response>>,
{ {
self.add_message_handler(model, move |handle, envelope, this, cx| { self.add_message_handler(model, move |handle, envelope, this, cx| {
Self::respond_to_request( Self::respond_to_request(
@ -615,9 +608,9 @@ impl Client {
pub fn add_model_message_handler<M, E, H, F>(self: &Arc<Self>, handler: H) pub fn add_model_message_handler<M, E, H, F>(self: &Arc<Self>, handler: H)
where where
M: EntityMessage, M: EntityMessage,
E: 'static + Send, E: 'static,
H: 'static + Send + Sync + Fn(Model<E>, TypedEnvelope<M>, Arc<Self>, AsyncAppContext) -> F, H: 'static + Fn(Model<E>, TypedEnvelope<M>, Arc<Self>, AsyncAppContext) -> F,
F: 'static + Future<Output = Result<()>> + Send, F: 'static + Future<Output = Result<()>>,
{ {
self.add_entity_message_handler::<M, E, _, _>(move |subscriber, message, client, cx| { self.add_entity_message_handler::<M, E, _, _>(move |subscriber, message, client, cx| {
handler(subscriber.downcast::<E>().unwrap(), message, client, cx) handler(subscriber.downcast::<E>().unwrap(), message, client, cx)
@ -627,9 +620,9 @@ impl Client {
fn add_entity_message_handler<M, E, H, F>(self: &Arc<Self>, handler: H) fn add_entity_message_handler<M, E, H, F>(self: &Arc<Self>, handler: H)
where where
M: EntityMessage, M: EntityMessage,
E: 'static + Send, E: 'static,
H: 'static + Send + Sync + Fn(AnyModel, TypedEnvelope<M>, Arc<Self>, AsyncAppContext) -> F, H: 'static + Fn(AnyModel, TypedEnvelope<M>, Arc<Self>, AsyncAppContext) -> F,
F: 'static + Future<Output = Result<()>> + Send, F: 'static + Future<Output = Result<()>>,
{ {
let model_type_id = TypeId::of::<E>(); let model_type_id = TypeId::of::<E>();
let message_type_id = TypeId::of::<M>(); let message_type_id = TypeId::of::<M>();
@ -655,7 +648,7 @@ impl Client {
message_type_id, message_type_id,
Arc::new(move |handle, envelope, client, cx| { Arc::new(move |handle, envelope, client, cx| {
let envelope = envelope.into_any().downcast::<TypedEnvelope<M>>().unwrap(); let envelope = envelope.into_any().downcast::<TypedEnvelope<M>>().unwrap();
handler(handle, *envelope, client.clone(), cx).boxed() handler(handle, *envelope, client.clone(), cx).boxed_local()
}), }),
); );
if prev_handler.is_some() { if prev_handler.is_some() {
@ -666,9 +659,9 @@ impl Client {
pub fn add_model_request_handler<M, E, H, F>(self: &Arc<Self>, handler: H) pub fn add_model_request_handler<M, E, H, F>(self: &Arc<Self>, handler: H)
where where
M: EntityMessage + RequestMessage, M: EntityMessage + RequestMessage,
E: 'static + Send, E: 'static,
H: 'static + Send + Sync + Fn(Model<E>, TypedEnvelope<M>, Arc<Self>, AsyncAppContext) -> F, H: 'static + Fn(Model<E>, TypedEnvelope<M>, Arc<Self>, AsyncAppContext) -> F,
F: 'static + Future<Output = Result<M::Response>> + Send, F: 'static + Future<Output = Result<M::Response>>,
{ {
self.add_model_message_handler(move |entity, envelope, client, cx| { self.add_model_message_handler(move |entity, envelope, client, cx| {
Self::respond_to_request::<M, _>( Self::respond_to_request::<M, _>(
@ -705,7 +698,7 @@ impl Client {
read_credentials_from_keychain(cx).await.is_some() read_credentials_from_keychain(cx).await.is_some()
} }
#[async_recursion] #[async_recursion(?Send)]
pub async fn authenticate_and_connect( pub async fn authenticate_and_connect(
self: &Arc<Self>, self: &Arc<Self>,
try_keychain: bool, try_keychain: bool,
@ -1050,7 +1043,7 @@ impl Client {
write!(&mut url, "&impersonate={}", impersonate_login).unwrap(); write!(&mut url, "&impersonate={}", impersonate_login).unwrap();
} }
cx.run_on_main(move |cx| cx.open_url(&url))?.await; cx.update(|cx| cx.open_url(&url))?;
// Receive the HTTP request from the user's browser. Retrieve the user id and encrypted // Receive the HTTP request from the user's browser. Retrieve the user id and encrypted
// access token from the query params. // access token from the query params.
@ -1101,7 +1094,7 @@ impl Client {
let access_token = private_key let access_token = private_key
.decrypt_string(&access_token) .decrypt_string(&access_token)
.context("failed to decrypt access token")?; .context("failed to decrypt access token")?;
cx.run_on_main(|cx| cx.activate(true))?.await; cx.update(|cx| cx.activate(true))?;
Ok(Credentials { Ok(Credentials {
user_id: user_id.parse()?, user_id: user_id.parse()?,
@ -1293,7 +1286,7 @@ impl Client {
sender_id, sender_id,
type_name type_name
); );
cx.spawn_on_main(move |_| async move { cx.spawn(move |_| async move {
match future.await { match future.await {
Ok(()) => { Ok(()) => {
log::debug!( log::debug!(
@ -1332,9 +1325,8 @@ async fn read_credentials_from_keychain(cx: &AsyncAppContext) -> Option<Credenti
} }
let (user_id, access_token) = cx let (user_id, access_token) = cx
.run_on_main(|cx| cx.read_credentials(&ZED_SERVER_URL).log_err().flatten()) .update(|cx| cx.read_credentials(&ZED_SERVER_URL).log_err().flatten())
.ok()? .ok()??;
.await?;
Some(Credentials { Some(Credentials {
user_id: user_id.parse().ok()?, user_id: user_id.parse().ok()?,
@ -1346,19 +1338,17 @@ async fn write_credentials_to_keychain(
credentials: Credentials, credentials: Credentials,
cx: &AsyncAppContext, cx: &AsyncAppContext,
) -> Result<()> { ) -> Result<()> {
cx.run_on_main(move |cx| { cx.update(move |cx| {
cx.write_credentials( cx.write_credentials(
&ZED_SERVER_URL, &ZED_SERVER_URL,
&credentials.user_id.to_string(), &credentials.user_id.to_string(),
credentials.access_token.as_bytes(), credentials.access_token.as_bytes(),
) )
})? })?
.await
} }
async fn delete_credentials_from_keychain(cx: &AsyncAppContext) -> Result<()> { async fn delete_credentials_from_keychain(cx: &AsyncAppContext) -> Result<()> {
cx.run_on_main(move |cx| cx.delete_credentials(&ZED_SERVER_URL))? cx.update(move |cx| cx.delete_credentials(&ZED_SERVER_URL))?
.await
} }
const WORKTREE_URL_PREFIX: &str = "zed://worktrees/"; const WORKTREE_URL_PREFIX: &str = "zed://worktrees/";
@ -1430,7 +1420,7 @@ mod tests {
// Time out when client tries to connect. // Time out when client tries to connect.
client.override_authenticate(move |cx| { client.override_authenticate(move |cx| {
cx.executor().spawn(async move { cx.background_executor().spawn(async move {
Ok(Credentials { Ok(Credentials {
user_id, user_id,
access_token: "token".into(), access_token: "token".into(),
@ -1438,7 +1428,7 @@ mod tests {
}) })
}); });
client.override_establish_connection(|_, cx| { client.override_establish_connection(|_, cx| {
cx.executor().spawn(async move { cx.background_executor().spawn(async move {
future::pending::<()>().await; future::pending::<()>().await;
unreachable!() unreachable!()
}) })
@ -1472,7 +1462,7 @@ mod tests {
// Time out when re-establishing the connection. // Time out when re-establishing the connection.
server.allow_connections(); server.allow_connections();
client.override_establish_connection(|_, cx| { client.override_establish_connection(|_, cx| {
cx.executor().spawn(async move { cx.background_executor().spawn(async move {
future::pending::<()>().await; future::pending::<()>().await;
unreachable!() unreachable!()
}) })
@ -1504,7 +1494,7 @@ mod tests {
move |cx| { move |cx| {
let auth_count = auth_count.clone(); let auth_count = auth_count.clone();
let dropped_auth_count = dropped_auth_count.clone(); let dropped_auth_count = dropped_auth_count.clone();
cx.executor().spawn(async move { cx.background_executor().spawn(async move {
*auth_count.lock() += 1; *auth_count.lock() += 1;
let _drop = util::defer(move || *dropped_auth_count.lock() += 1); let _drop = util::defer(move || *dropped_auth_count.lock() += 1);
future::pending::<()>().await; future::pending::<()>().await;

View file

@ -1,5 +1,5 @@
use crate::{TelemetrySettings, ZED_SECRET_CLIENT_TOKEN, ZED_SERVER_URL}; use crate::{TelemetrySettings, ZED_SECRET_CLIENT_TOKEN, ZED_SERVER_URL};
use gpui2::{serde_json, AppContext, AppMetadata, Executor, Task}; use gpui2::{serde_json, AppContext, AppMetadata, BackgroundExecutor, Task};
use lazy_static::lazy_static; use lazy_static::lazy_static;
use parking_lot::Mutex; use parking_lot::Mutex;
use serde::Serialize; use serde::Serialize;
@ -14,7 +14,7 @@ use util::{channel::ReleaseChannel, TryFutureExt};
pub struct Telemetry { pub struct Telemetry {
http_client: Arc<dyn HttpClient>, http_client: Arc<dyn HttpClient>,
executor: Executor, executor: BackgroundExecutor,
state: Mutex<TelemetryState>, state: Mutex<TelemetryState>,
} }

View file

@ -266,9 +266,9 @@ impl<'a> EditorLspTestContext<'a> {
) -> futures::channel::mpsc::UnboundedReceiver<()> ) -> futures::channel::mpsc::UnboundedReceiver<()>
where where
T: 'static + request::Request, T: 'static + request::Request,
T::Params: 'static, T::Params: 'static + Send,
F: 'static + FnMut(lsp::Url, T::Params, gpui::AsyncAppContext) -> Fut, F: 'static + Send + FnMut(lsp::Url, T::Params, gpui::AsyncAppContext) -> Fut,
Fut: 'static + Future<Output = Result<T::Result>>, Fut: 'static + Send + Future<Output = Result<T::Result>>,
{ {
let url = self.buffer_lsp_url.clone(); let url = self.buffer_lsp_url.clone();
self.lsp.handle_request::<T, _, _>(move |params, cx| { self.lsp.handle_request::<T, _, _>(move |params, cx| {

View file

@ -2,7 +2,7 @@ use crate::{
matcher::{Match, MatchCandidate, Matcher}, matcher::{Match, MatchCandidate, Matcher},
CharBag, CharBag,
}; };
use gpui2::Executor; use gpui2::BackgroundExecutor;
use std::{ use std::{
borrow::Cow, borrow::Cow,
cmp::{self, Ordering}, cmp::{self, Ordering},
@ -83,7 +83,7 @@ pub async fn match_strings(
smart_case: bool, smart_case: bool,
max_results: usize, max_results: usize,
cancel_flag: &AtomicBool, cancel_flag: &AtomicBool,
executor: Executor, executor: BackgroundExecutor,
) -> Vec<StringMatch> { ) -> Vec<StringMatch> {
if candidates.is_empty() || max_results == 0 { if candidates.is_empty() || max_results == 0 {
return Default::default(); return Default::default();

View file

@ -107,11 +107,11 @@ impl App {
} }
type ActionBuilder = fn(json: Option<serde_json::Value>) -> anyhow::Result<Box<dyn Action>>; type ActionBuilder = fn(json: Option<serde_json::Value>) -> anyhow::Result<Box<dyn Action>>;
type FrameCallback = Box<dyn FnOnce(&mut WindowContext) + Send>; type FrameCallback = Box<dyn FnOnce(&mut WindowContext)>;
type Handler = Box<dyn FnMut(&mut AppContext) -> bool + Send + 'static>; type Handler = Box<dyn FnMut(&mut AppContext) -> bool + 'static>;
type Listener = Box<dyn FnMut(&dyn Any, &mut AppContext) -> bool + Send + 'static>; type Listener = Box<dyn FnMut(&dyn Any, &mut AppContext) -> bool + 'static>;
type QuitHandler = Box<dyn FnMut(&mut AppContext) -> BoxFuture<'static, ()> + Send + 'static>; type QuitHandler = Box<dyn FnMut(&mut AppContext) -> BoxFuture<'static, ()> + 'static>;
type ReleaseListener = Box<dyn FnMut(&mut dyn Any, &mut AppContext) + Send + 'static>; type ReleaseListener = Box<dyn FnMut(&mut dyn Any, &mut AppContext) + 'static>;
pub struct AppContext { pub struct AppContext {
this: Weak<RefCell<AppContext>>, this: Weak<RefCell<AppContext>>,
@ -133,7 +133,7 @@ pub struct AppContext {
pub(crate) windows: SlotMap<WindowId, Option<Window>>, pub(crate) windows: SlotMap<WindowId, Option<Window>>,
pub(crate) keymap: Arc<Mutex<Keymap>>, pub(crate) keymap: Arc<Mutex<Keymap>>,
pub(crate) global_action_listeners: pub(crate) global_action_listeners:
HashMap<TypeId, Vec<Box<dyn Fn(&dyn Action, DispatchPhase, &mut Self) + Send>>>, HashMap<TypeId, Vec<Box<dyn Fn(&dyn Action, DispatchPhase, &mut Self)>>>,
action_builders: HashMap<SharedString, ActionBuilder>, action_builders: HashMap<SharedString, ActionBuilder>,
pending_effects: VecDeque<Effect>, pending_effects: VecDeque<Effect>,
pub(crate) pending_notifications: HashSet<EntityId>, pub(crate) pending_notifications: HashSet<EntityId>,
@ -295,7 +295,7 @@ impl AppContext {
pub fn open_window<V: Render>( pub fn open_window<V: Render>(
&mut self, &mut self,
options: crate::WindowOptions, options: crate::WindowOptions,
build_root_view: impl FnOnce(&mut WindowContext) -> View<V> + Send + 'static, build_root_view: impl FnOnce(&mut WindowContext) -> View<V> + 'static,
) -> WindowHandle<V> { ) -> WindowHandle<V> {
self.update(|cx| { self.update(|cx| {
let id = cx.windows.insert(None); let id = cx.windows.insert(None);
@ -520,7 +520,7 @@ impl AppContext {
.retain(&type_id, |observer| observer(self)); .retain(&type_id, |observer| observer(self));
} }
fn apply_defer_effect(&mut self, callback: Box<dyn FnOnce(&mut Self) + Send + 'static>) { fn apply_defer_effect(&mut self, callback: Box<dyn FnOnce(&mut Self) + 'static>) {
callback(self); callback(self);
} }
@ -551,7 +551,7 @@ impl AppContext {
/// Schedules the given function to be run at the end of the current effect cycle, allowing entities /// Schedules the given function to be run at the end of the current effect cycle, allowing entities
/// that are currently on the stack to be returned to the app. /// that are currently on the stack to be returned to the app.
pub fn defer(&mut self, f: impl FnOnce(&mut AppContext) + 'static + Send) { pub fn defer(&mut self, f: impl FnOnce(&mut AppContext) + 'static) {
self.push_effect(Effect::Defer { self.push_effect(Effect::Defer {
callback: Box::new(f), callback: Box::new(f),
}); });
@ -639,7 +639,7 @@ impl AppContext {
/// Register a callback to be invoked when a global of the given type is updated. /// Register a callback to be invoked when a global of the given type is updated.
pub fn observe_global<G: 'static>( pub fn observe_global<G: 'static>(
&mut self, &mut self,
mut f: impl FnMut(&mut Self) + Send + 'static, mut f: impl FnMut(&mut Self) + 'static,
) -> Subscription { ) -> Subscription {
self.global_observers.insert( self.global_observers.insert(
TypeId::of::<G>(), TypeId::of::<G>(),
@ -686,7 +686,7 @@ impl AppContext {
} }
/// Register a global listener for actions invoked via the keyboard. /// Register a global listener for actions invoked via the keyboard.
pub fn on_action<A: Action>(&mut self, listener: impl Fn(&A, &mut Self) + Send + 'static) { pub fn on_action<A: Action>(&mut self, listener: impl Fn(&A, &mut Self) + 'static) {
self.global_action_listeners self.global_action_listeners
.entry(TypeId::of::<A>()) .entry(TypeId::of::<A>())
.or_default() .or_default()
@ -778,7 +778,7 @@ pub(crate) enum Effect {
global_type: TypeId, global_type: TypeId,
}, },
Defer { Defer {
callback: Box<dyn FnOnce(&mut AppContext) + Send + 'static>, callback: Box<dyn FnOnce(&mut AppContext) + 'static>,
}, },
} }

View file

@ -218,8 +218,8 @@ impl<V> Component<V> for AnyElement<V> {
impl<V, E, F> Element<V> for Option<F> impl<V, E, F> Element<V> for Option<F>
where where
V: 'static, V: 'static,
E: 'static + Component<V> + Send, E: 'static + Component<V>,
F: FnOnce(&mut V, &mut ViewContext<'_, '_, V>) -> E + Send + 'static, F: FnOnce(&mut V, &mut ViewContext<'_, '_, V>) -> E + 'static,
{ {
type ElementState = AnyElement<V>; type ElementState = AnyElement<V>;
@ -262,8 +262,8 @@ where
impl<V, E, F> Component<V> for Option<F> impl<V, E, F> Component<V> for Option<F>
where where
V: 'static, V: 'static,
E: 'static + Component<V> + Send, E: 'static + Component<V>,
F: FnOnce(&mut V, &mut ViewContext<'_, '_, V>) -> E + Send + 'static, F: FnOnce(&mut V, &mut ViewContext<'_, '_, V>) -> E + 'static,
{ {
fn render(self) -> AnyElement<V> { fn render(self) -> AnyElement<V> {
AnyElement::new(self) AnyElement::new(self)
@ -273,8 +273,8 @@ where
impl<V, E, F> Component<V> for F impl<V, E, F> Component<V> for F
where where
V: 'static, V: 'static,
E: 'static + Component<V> + Send, E: 'static + Component<V>,
F: FnOnce(&mut V, &mut ViewContext<'_, '_, V>) -> E + Send + 'static, F: FnOnce(&mut V, &mut ViewContext<'_, '_, V>) -> E + 'static,
{ {
fn render(self) -> AnyElement<V> { fn render(self) -> AnyElement<V> {
AnyElement::new(Some(self)) AnyElement::new(Some(self))

View file

@ -36,6 +36,10 @@ pub fn derive_component(input: TokenStream) -> TokenStream {
} }
}; };
if name == "CollabPanel" {
println!("{}", expanded)
}
TokenStream::from(expanded) TokenStream::from(expanded)
} }

View file

@ -89,8 +89,8 @@ pub fn test(args: TokenStream, function: TokenStream) -> TokenStream {
inner_fn_args.extend(quote!(rand::SeedableRng::seed_from_u64(_seed),)); inner_fn_args.extend(quote!(rand::SeedableRng::seed_from_u64(_seed),));
continue; continue;
} }
Some("Executor") => { Some("BackgroundExecutor") => {
inner_fn_args.extend(quote!(gpui2::Executor::new( inner_fn_args.extend(quote!(gpui2::BackgroundExecutor::new(
std::sync::Arc::new(dispatcher.clone()) std::sync::Arc::new(dispatcher.clone())
),)); ),));
continue; continue;
@ -134,7 +134,7 @@ pub fn test(args: TokenStream, function: TokenStream) -> TokenStream {
#num_iterations as u64, #num_iterations as u64,
#max_retries, #max_retries,
&mut |dispatcher, _seed| { &mut |dispatcher, _seed| {
let executor = gpui2::Executor::new(std::sync::Arc::new(dispatcher.clone())); let executor = gpui2::BackgroundExecutor::new(std::sync::Arc::new(dispatcher.clone()));
#cx_vars #cx_vars
executor.block(#inner_fn_name(#inner_fn_args)); executor.block(#inner_fn_name(#inner_fn_args));
#cx_teardowns #cx_teardowns
@ -170,7 +170,7 @@ pub fn test(args: TokenStream, function: TokenStream) -> TokenStream {
let mut #cx_varname = gpui2::TestAppContext::new( let mut #cx_varname = gpui2::TestAppContext::new(
dispatcher.clone() dispatcher.clone()
); );
let mut #cx_varname_lock = #cx_varname.app.lock(); let mut #cx_varname_lock = #cx_varname.app.borrow_mut();
)); ));
inner_fn_args.extend(quote!(&mut #cx_varname_lock,)); inner_fn_args.extend(quote!(&mut #cx_varname_lock,));
cx_teardowns.extend(quote!( cx_teardowns.extend(quote!(

View file

@ -7,9 +7,7 @@ use util::ResultExt;
// actions!(cli, [Install]); // actions!(cli, [Install]);
pub async fn install_cli(cx: &AsyncAppContext) -> Result<()> { pub async fn install_cli(cx: &AsyncAppContext) -> Result<()> {
let cli_path = cx let cli_path = cx.update(|cx| cx.path_for_auxiliary_executable("cli"))??;
.run_on_main(|cx| cx.path_for_auxiliary_executable("cli"))?
.await?;
let link_path = Path::new("/usr/local/bin/zed"); let link_path = Path::new("/usr/local/bin/zed");
let bin_dir_path = link_path.parent().unwrap(); let bin_dir_path = link_path.parent().unwrap();

View file

@ -1,5 +1,5 @@
use fuzzy2::{StringMatch, StringMatchCandidate}; use fuzzy2::{StringMatch, StringMatchCandidate};
use gpui2::{Executor, HighlightStyle}; use gpui2::{BackgroundExecutor, HighlightStyle};
use std::ops::Range; use std::ops::Range;
#[derive(Debug)] #[derive(Debug)]
@ -57,7 +57,7 @@ impl<T> Outline<T> {
} }
} }
pub async fn search(&self, query: &str, executor: Executor) -> Vec<StringMatch> { pub async fn search(&self, query: &str, executor: BackgroundExecutor) -> Vec<StringMatch> {
let query = query.trim_start(); let query = query.trim_start();
let is_path_query = query.contains(' '); let is_path_query = query.contains(' ');
let smart_case = query.chars().any(|c| c.is_uppercase()); let smart_case = query.chars().any(|c| c.is_uppercase());

View file

@ -1047,8 +1047,9 @@ impl FakeLanguageServer {
.on_request::<T, _, _>(move |params, cx| { .on_request::<T, _, _>(move |params, cx| {
let result = handler(params, cx.clone()); let result = handler(params, cx.clone());
let responded_tx = responded_tx.clone(); let responded_tx = responded_tx.clone();
let executor = cx.background_executor().clone();
async move { async move {
cx.background_executor().simulate_random_delay().await; executor.simulate_random_delay().await;
let result = result.await; let result = result.await;
responded_tx.unbounded_send(()).ok(); responded_tx.unbounded_send(()).ok();
result result

View file

@ -51,8 +51,8 @@ use thiserror::Error;
use gpui2::{ use gpui2::{
px, AnyWindowHandle, AppContext, Bounds, ClipboardItem, EventEmitter, Hsla, Keystroke, px, AnyWindowHandle, AppContext, Bounds, ClipboardItem, EventEmitter, Hsla, Keystroke,
MainThread, ModelContext, Modifiers, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, ModelContext, Modifiers, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Pixels,
Pixels, Point, ScrollWheelEvent, Size, Task, TouchPhase, Point, ScrollWheelEvent, Size, Task, TouchPhase,
}; };
use crate::mappings::{colors::to_alac_rgb, keys::to_esc_str}; use crate::mappings::{colors::to_alac_rgb, keys::to_esc_str};
@ -403,7 +403,7 @@ impl TerminalBuilder {
pub fn subscribe(mut self, cx: &mut ModelContext<Terminal>) -> Terminal { pub fn subscribe(mut self, cx: &mut ModelContext<Terminal>) -> Terminal {
//Event loop //Event loop
cx.spawn_on_main(|this, mut cx| async move { cx.spawn(|this, mut cx| async move {
use futures::StreamExt; use futures::StreamExt;
while let Some(event) = self.events_rx.next().await { while let Some(event) = self.events_rx.next().await {
@ -414,7 +414,10 @@ impl TerminalBuilder {
'outer: loop { 'outer: loop {
let mut events = vec![]; let mut events = vec![];
let mut timer = cx.executor().timer(Duration::from_millis(4)).fuse(); let mut timer = cx
.background_executor()
.timer(Duration::from_millis(4))
.fuse();
let mut wakeup = false; let mut wakeup = false;
loop { loop {
futures::select_biased! { futures::select_biased! {
@ -551,7 +554,7 @@ pub struct Terminal {
} }
impl Terminal { impl Terminal {
fn process_event(&mut self, event: &AlacTermEvent, cx: &mut MainThread<ModelContext<Self>>) { fn process_event(&mut self, event: &AlacTermEvent, cx: &mut ModelContext<Self>) {
match event { match event {
AlacTermEvent::Title(title) => { AlacTermEvent::Title(title) => {
self.breadcrumb_text = title.to_string(); self.breadcrumb_text = title.to_string();
@ -708,8 +711,7 @@ impl Terminal {
InternalEvent::Copy => { InternalEvent::Copy => {
if let Some(txt) = term.selection_to_string() { if let Some(txt) = term.selection_to_string() {
cx.run_on_main(|cx| cx.write_to_clipboard(ClipboardItem::new(txt))) cx.write_to_clipboard(ClipboardItem::new(txt))
.detach();
} }
} }
InternalEvent::ScrollToAlacPoint(point) => { InternalEvent::ScrollToAlacPoint(point) => {
@ -1189,7 +1191,7 @@ impl Terminal {
&mut self, &mut self,
e: &MouseUpEvent, e: &MouseUpEvent,
origin: Point<Pixels>, origin: Point<Pixels>,
cx: &mut MainThread<ModelContext<Self>>, cx: &mut ModelContext<Self>,
) { ) {
let setting = TerminalSettings::get_global(cx); let setting = TerminalSettings::get_global(cx);

View file

@ -133,9 +133,9 @@ impl<'a> VimTestContext<'a> {
) -> futures::channel::mpsc::UnboundedReceiver<()> ) -> futures::channel::mpsc::UnboundedReceiver<()>
where where
T: 'static + request::Request, T: 'static + request::Request,
T::Params: 'static, T::Params: 'static + Send,
F: 'static + FnMut(lsp::Url, T::Params, gpui::AsyncAppContext) -> Fut, F: 'static + Send + FnMut(lsp::Url, T::Params, gpui::AsyncAppContext) -> Fut,
Fut: 'static + Future<Output = Result<T::Result>>, Fut: 'static + Send + Future<Output = Result<T::Result>>,
{ {
self.cx.handle_request::<T, F, Fut>(handler) self.cx.handle_request::<T, F, Fut>(handler)
} }