wip
This commit is contained in:
parent
57ffa8201e
commit
dd1a2a9e44
16 changed files with 138 additions and 181 deletions
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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| {
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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>,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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))
|
||||||
|
|
|
@ -36,6 +36,10 @@ pub fn derive_component(input: TokenStream) -> TokenStream {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if name == "CollabPanel" {
|
||||||
|
println!("{}", expanded)
|
||||||
|
}
|
||||||
|
|
||||||
TokenStream::from(expanded)
|
TokenStream::from(expanded)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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!(
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue