diff --git a/Cargo.lock b/Cargo.lock index 6d716705ba..1865c0bb28 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -108,6 +108,33 @@ dependencies = [ "util", ] +[[package]] +name = "ai2" +version = "0.1.0" +dependencies = [ + "anyhow", + "async-trait", + "bincode", + "futures 0.3.28", + "gpui2", + "isahc", + "language2", + "lazy_static", + "log", + "matrixmultiply", + "ordered-float 2.10.0", + "parking_lot 0.11.2", + "parse_duration", + "postage", + "rand 0.8.5", + "regex", + "rusqlite", + "serde", + "serde_json", + "tiktoken-rs", + "util", +] + [[package]] name = "alacritty_config" version = "0.1.2-dev" @@ -1138,7 +1165,7 @@ dependencies = [ "audio2", "client2", "collections", - "fs", + "fs2", "futures 0.3.28", "gpui2", "language2", @@ -4795,6 +4822,13 @@ dependencies = [ "gpui", ] +[[package]] +name = "menu2" +version = "0.1.0" +dependencies = [ + "gpui2", +] + [[package]] name = "metal" version = "0.21.0" @@ -6000,7 +6034,7 @@ dependencies = [ "anyhow", "client2", "collections", - "fs", + "fs2", "futures 0.3.28", "gpui2", "language2", @@ -6167,7 +6201,7 @@ dependencies = [ "ctor", "db2", "env_logger 0.9.3", - "fs", + "fs2", "fsevent", "futures 0.3.28", "fuzzy2", @@ -8740,6 +8774,7 @@ version = "0.1.0" dependencies = [ "anyhow", "clap 4.4.4", + "convert_case 0.6.0", "gpui2", "log", "rust-embed", @@ -10932,6 +10967,7 @@ dependencies = [ name = "zed2" version = "0.109.0" dependencies = [ + "ai2", "anyhow", "async-compression", "async-recursion 0.3.2", diff --git a/Cargo.toml b/Cargo.toml index 2d48e171cf..e8ce7634f4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -59,6 +59,7 @@ members = [ "crates/lsp2", "crates/media", "crates/menu", + "crates/menu2", "crates/multi_buffer", "crates/node_runtime", "crates/notifications", diff --git a/crates/Cargo.toml b/crates/Cargo.toml new file mode 100644 index 0000000000..fb49a4b515 --- /dev/null +++ b/crates/Cargo.toml @@ -0,0 +1,38 @@ +[package] +name = "ai" +version = "0.1.0" +edition = "2021" +publish = false + +[lib] +path = "src/ai.rs" +doctest = false + +[features] +test-support = [] + +[dependencies] +gpui = { path = "../gpui" } +util = { path = "../util" } +language = { path = "../language" } +async-trait.workspace = true +anyhow.workspace = true +futures.workspace = true +lazy_static.workspace = true +ordered-float.workspace = true +parking_lot.workspace = true +isahc.workspace = true +regex.workspace = true +serde.workspace = true +serde_json.workspace = true +postage.workspace = true +rand.workspace = true +log.workspace = true +parse_duration = "2.1.1" +tiktoken-rs = "0.5.0" +matrixmultiply = "0.3.7" +rusqlite = { version = "0.29.0", features = ["blob", "array", "modern_sqlite"] } +bincode = "1.3.3" + +[dev-dependencies] +gpui = { path = "../gpui", features = ["test-support"] } diff --git a/crates/ai/Cargo.toml b/crates/ai/Cargo.toml index b24c4e5ece..fb49a4b515 100644 --- a/crates/ai/Cargo.toml +++ b/crates/ai/Cargo.toml @@ -8,6 +8,9 @@ publish = false path = "src/ai.rs" doctest = false +[features] +test-support = [] + [dependencies] gpui = { path = "../gpui" } util = { path = "../util" } diff --git a/crates/ai/src/ai.rs b/crates/ai/src/ai.rs index f168c15793..dda22d2a1d 100644 --- a/crates/ai/src/ai.rs +++ b/crates/ai/src/ai.rs @@ -1,4 +1,8 @@ +pub mod auth; pub mod completion; pub mod embedding; pub mod models; -pub mod templates; +pub mod prompts; +pub mod providers; +#[cfg(any(test, feature = "test-support"))] +pub mod test; diff --git a/crates/ai/src/auth.rs b/crates/ai/src/auth.rs new file mode 100644 index 0000000000..c6256df216 --- /dev/null +++ b/crates/ai/src/auth.rs @@ -0,0 +1,15 @@ +use gpui::AppContext; + +#[derive(Clone, Debug)] +pub enum ProviderCredential { + Credentials { api_key: String }, + NoCredentials, + NotNeeded, +} + +pub trait CredentialProvider: Send + Sync { + fn has_credentials(&self) -> bool; + fn retrieve_credentials(&self, cx: &AppContext) -> ProviderCredential; + fn save_credentials(&self, cx: &AppContext, credential: ProviderCredential); + fn delete_credentials(&self, cx: &AppContext); +} diff --git a/crates/ai/src/completion.rs b/crates/ai/src/completion.rs index de6ce9da71..30a60fcf1d 100644 --- a/crates/ai/src/completion.rs +++ b/crates/ai/src/completion.rs @@ -1,214 +1,23 @@ -use anyhow::{anyhow, Result}; -use futures::{ - future::BoxFuture, io::BufReader, stream::BoxStream, AsyncBufReadExt, AsyncReadExt, FutureExt, - Stream, StreamExt, -}; -use gpui::executor::Background; -use isahc::{http::StatusCode, Request, RequestExt}; -use serde::{Deserialize, Serialize}; -use std::{ - fmt::{self, Display}, - io, - sync::Arc, -}; +use anyhow::Result; +use futures::{future::BoxFuture, stream::BoxStream}; -pub const OPENAI_API_URL: &'static str = "https://api.openai.com/v1"; +use crate::{auth::CredentialProvider, models::LanguageModel}; -#[derive(Clone, Copy, Serialize, Deserialize, Debug, Eq, PartialEq)] -#[serde(rename_all = "lowercase")] -pub enum Role { - User, - Assistant, - System, +pub trait CompletionRequest: Send + Sync { + fn data(&self) -> serde_json::Result; } -impl Role { - pub fn cycle(&mut self) { - *self = match self { - Role::User => Role::Assistant, - Role::Assistant => Role::System, - Role::System => Role::User, - } - } -} - -impl Display for Role { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Role::User => write!(f, "User"), - Role::Assistant => write!(f, "Assistant"), - Role::System => write!(f, "System"), - } - } -} - -#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)] -pub struct RequestMessage { - pub role: Role, - pub content: String, -} - -#[derive(Debug, Default, Serialize)] -pub struct OpenAIRequest { - pub model: String, - pub messages: Vec, - pub stream: bool, - pub stop: Vec, - pub temperature: f32, -} - -#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)] -pub struct ResponseMessage { - pub role: Option, - pub content: Option, -} - -#[derive(Deserialize, Debug)] -pub struct OpenAIUsage { - pub prompt_tokens: u32, - pub completion_tokens: u32, - pub total_tokens: u32, -} - -#[derive(Deserialize, Debug)] -pub struct ChatChoiceDelta { - pub index: u32, - pub delta: ResponseMessage, - pub finish_reason: Option, -} - -#[derive(Deserialize, Debug)] -pub struct OpenAIResponseStreamEvent { - pub id: Option, - pub object: String, - pub created: u32, - pub model: String, - pub choices: Vec, - pub usage: Option, -} - -pub async fn stream_completion( - api_key: String, - executor: Arc, - mut request: OpenAIRequest, -) -> Result>> { - request.stream = true; - - let (tx, rx) = futures::channel::mpsc::unbounded::>(); - - let json_data = serde_json::to_string(&request)?; - let mut response = Request::post(format!("{OPENAI_API_URL}/chat/completions")) - .header("Content-Type", "application/json") - .header("Authorization", format!("Bearer {}", api_key)) - .body(json_data)? - .send_async() - .await?; - - let status = response.status(); - if status == StatusCode::OK { - executor - .spawn(async move { - let mut lines = BufReader::new(response.body_mut()).lines(); - - fn parse_line( - line: Result, - ) -> Result> { - if let Some(data) = line?.strip_prefix("data: ") { - let event = serde_json::from_str(&data)?; - Ok(Some(event)) - } else { - Ok(None) - } - } - - while let Some(line) = lines.next().await { - if let Some(event) = parse_line(line).transpose() { - let done = event.as_ref().map_or(false, |event| { - event - .choices - .last() - .map_or(false, |choice| choice.finish_reason.is_some()) - }); - if tx.unbounded_send(event).is_err() { - break; - } - - if done { - break; - } - } - } - - anyhow::Ok(()) - }) - .detach(); - - Ok(rx) - } else { - let mut body = String::new(); - response.body_mut().read_to_string(&mut body).await?; - - #[derive(Deserialize)] - struct OpenAIResponse { - error: OpenAIError, - } - - #[derive(Deserialize)] - struct OpenAIError { - message: String, - } - - match serde_json::from_str::(&body) { - Ok(response) if !response.error.message.is_empty() => Err(anyhow!( - "Failed to connect to OpenAI API: {}", - response.error.message, - )), - - _ => Err(anyhow!( - "Failed to connect to OpenAI API: {} {}", - response.status(), - body, - )), - } - } -} - -pub trait CompletionProvider { +pub trait CompletionProvider: CredentialProvider { + fn base_model(&self) -> Box; fn complete( &self, - prompt: OpenAIRequest, + prompt: Box, ) -> BoxFuture<'static, Result>>>; + fn box_clone(&self) -> Box; } -pub struct OpenAICompletionProvider { - api_key: String, - executor: Arc, -} - -impl OpenAICompletionProvider { - pub fn new(api_key: String, executor: Arc) -> Self { - Self { api_key, executor } - } -} - -impl CompletionProvider for OpenAICompletionProvider { - fn complete( - &self, - prompt: OpenAIRequest, - ) -> BoxFuture<'static, Result>>> { - let request = stream_completion(self.api_key.clone(), self.executor.clone(), prompt); - async move { - let response = request.await?; - let stream = response - .filter_map(|response| async move { - match response { - Ok(mut response) => Some(Ok(response.choices.pop()?.delta.content?)), - Err(error) => Some(Err(error)), - } - }) - .boxed(); - Ok(stream) - } - .boxed() +impl Clone for Box { + fn clone(&self) -> Box { + self.box_clone() } } diff --git a/crates/ai/src/embedding.rs b/crates/ai/src/embedding.rs index b791414ba2..6768b7ce7b 100644 --- a/crates/ai/src/embedding.rs +++ b/crates/ai/src/embedding.rs @@ -1,32 +1,13 @@ -use anyhow::{anyhow, Result}; +use std::time::Instant; + +use anyhow::Result; use async_trait::async_trait; -use futures::AsyncReadExt; -use gpui::executor::Background; -use gpui::{serde_json, AppContext}; -use isahc::http::StatusCode; -use isahc::prelude::Configurable; -use isahc::{AsyncBody, Response}; -use lazy_static::lazy_static; use ordered_float::OrderedFloat; -use parking_lot::Mutex; -use parse_duration::parse; -use postage::watch; use rusqlite::types::{FromSql, FromSqlResult, ToSqlOutput, ValueRef}; use rusqlite::ToSql; -use serde::{Deserialize, Serialize}; -use std::env; -use std::ops::Add; -use std::sync::Arc; -use std::time::{Duration, Instant}; -use tiktoken_rs::{cl100k_base, CoreBPE}; -use util::http::{HttpClient, Request}; -use util::ResultExt; -use crate::completion::OPENAI_API_URL; - -lazy_static! { - static ref OPENAI_BPE_TOKENIZER: CoreBPE = cl100k_base().unwrap(); -} +use crate::auth::CredentialProvider; +use crate::models::LanguageModel; #[derive(Debug, PartialEq, Clone)] pub struct Embedding(pub Vec); @@ -87,301 +68,14 @@ impl Embedding { } } -#[derive(Clone)] -pub struct OpenAIEmbeddings { - pub client: Arc, - pub executor: Arc, - rate_limit_count_rx: watch::Receiver>, - rate_limit_count_tx: Arc>>>, -} - -#[derive(Serialize)] -struct OpenAIEmbeddingRequest<'a> { - model: &'static str, - input: Vec<&'a str>, -} - -#[derive(Deserialize)] -struct OpenAIEmbeddingResponse { - data: Vec, - usage: OpenAIEmbeddingUsage, -} - -#[derive(Debug, Deserialize)] -struct OpenAIEmbedding { - embedding: Vec, - index: usize, - object: String, -} - -#[derive(Deserialize)] -struct OpenAIEmbeddingUsage { - prompt_tokens: usize, - total_tokens: usize, -} - #[async_trait] -pub trait EmbeddingProvider: Sync + Send { - fn retrieve_credentials(&self, cx: &AppContext) -> Option; - async fn embed_batch( - &self, - spans: Vec, - api_key: Option, - ) -> Result>; +pub trait EmbeddingProvider: CredentialProvider { + fn base_model(&self) -> Box; + async fn embed_batch(&self, spans: Vec) -> Result>; fn max_tokens_per_batch(&self) -> usize; - fn truncate(&self, span: &str) -> (String, usize); fn rate_limit_expiration(&self) -> Option; } -pub struct DummyEmbeddings {} - -#[async_trait] -impl EmbeddingProvider for DummyEmbeddings { - fn retrieve_credentials(&self, _cx: &AppContext) -> Option { - Some("Dummy API KEY".to_string()) - } - fn rate_limit_expiration(&self) -> Option { - None - } - async fn embed_batch( - &self, - spans: Vec, - _api_key: Option, - ) -> Result> { - // 1024 is the OpenAI Embeddings size for ada models. - // the model we will likely be starting with. - let dummy_vec = Embedding::from(vec![0.32 as f32; 1536]); - return Ok(vec![dummy_vec; spans.len()]); - } - - fn max_tokens_per_batch(&self) -> usize { - OPENAI_INPUT_LIMIT - } - - fn truncate(&self, span: &str) -> (String, usize) { - let mut tokens = OPENAI_BPE_TOKENIZER.encode_with_special_tokens(span); - let token_count = tokens.len(); - let output = if token_count > OPENAI_INPUT_LIMIT { - tokens.truncate(OPENAI_INPUT_LIMIT); - let new_input = OPENAI_BPE_TOKENIZER.decode(tokens.clone()); - new_input.ok().unwrap_or_else(|| span.to_string()) - } else { - span.to_string() - }; - - (output, tokens.len()) - } -} - -const OPENAI_INPUT_LIMIT: usize = 8190; - -impl OpenAIEmbeddings { - pub fn new(client: Arc, executor: Arc) -> Self { - let (rate_limit_count_tx, rate_limit_count_rx) = watch::channel_with(None); - let rate_limit_count_tx = Arc::new(Mutex::new(rate_limit_count_tx)); - - OpenAIEmbeddings { - client, - executor, - rate_limit_count_rx, - rate_limit_count_tx, - } - } - - fn resolve_rate_limit(&self) { - let reset_time = *self.rate_limit_count_tx.lock().borrow(); - - if let Some(reset_time) = reset_time { - if Instant::now() >= reset_time { - *self.rate_limit_count_tx.lock().borrow_mut() = None - } - } - - log::trace!( - "resolving reset time: {:?}", - *self.rate_limit_count_tx.lock().borrow() - ); - } - - fn update_reset_time(&self, reset_time: Instant) { - let original_time = *self.rate_limit_count_tx.lock().borrow(); - - let updated_time = if let Some(original_time) = original_time { - if reset_time < original_time { - Some(reset_time) - } else { - Some(original_time) - } - } else { - Some(reset_time) - }; - - log::trace!("updating rate limit time: {:?}", updated_time); - - *self.rate_limit_count_tx.lock().borrow_mut() = updated_time; - } - async fn send_request( - &self, - api_key: &str, - spans: Vec<&str>, - request_timeout: u64, - ) -> Result> { - let request = Request::post("https://api.openai.com/v1/embeddings") - .redirect_policy(isahc::config::RedirectPolicy::Follow) - .timeout(Duration::from_secs(request_timeout)) - .header("Content-Type", "application/json") - .header("Authorization", format!("Bearer {}", api_key)) - .body( - serde_json::to_string(&OpenAIEmbeddingRequest { - input: spans.clone(), - model: "text-embedding-ada-002", - }) - .unwrap() - .into(), - )?; - - Ok(self.client.send(request).await?) - } -} - -#[async_trait] -impl EmbeddingProvider for OpenAIEmbeddings { - fn retrieve_credentials(&self, cx: &AppContext) -> Option { - if let Ok(api_key) = env::var("OPENAI_API_KEY") { - Some(api_key) - } else if let Some((_, api_key)) = cx - .platform() - .read_credentials(OPENAI_API_URL) - .log_err() - .flatten() - { - String::from_utf8(api_key).log_err() - } else { - None - } - } - - fn max_tokens_per_batch(&self) -> usize { - 50000 - } - - fn rate_limit_expiration(&self) -> Option { - *self.rate_limit_count_rx.borrow() - } - fn truncate(&self, span: &str) -> (String, usize) { - let mut tokens = OPENAI_BPE_TOKENIZER.encode_with_special_tokens(span); - let output = if tokens.len() > OPENAI_INPUT_LIMIT { - tokens.truncate(OPENAI_INPUT_LIMIT); - OPENAI_BPE_TOKENIZER - .decode(tokens.clone()) - .ok() - .unwrap_or_else(|| span.to_string()) - } else { - span.to_string() - }; - - (output, tokens.len()) - } - - async fn embed_batch( - &self, - spans: Vec, - api_key: Option, - ) -> Result> { - const BACKOFF_SECONDS: [usize; 4] = [3, 5, 15, 45]; - const MAX_RETRIES: usize = 4; - - let Some(api_key) = api_key else { - return Err(anyhow!("no open ai key provided")); - }; - - let mut request_number = 0; - let mut rate_limiting = false; - let mut request_timeout: u64 = 15; - let mut response: Response; - while request_number < MAX_RETRIES { - response = self - .send_request( - &api_key, - spans.iter().map(|x| &**x).collect(), - request_timeout, - ) - .await?; - - request_number += 1; - - match response.status() { - StatusCode::REQUEST_TIMEOUT => { - request_timeout += 5; - } - StatusCode::OK => { - let mut body = String::new(); - response.body_mut().read_to_string(&mut body).await?; - let response: OpenAIEmbeddingResponse = serde_json::from_str(&body)?; - - log::trace!( - "openai embedding completed. tokens: {:?}", - response.usage.total_tokens - ); - - // If we complete a request successfully that was previously rate_limited - // resolve the rate limit - if rate_limiting { - self.resolve_rate_limit() - } - - return Ok(response - .data - .into_iter() - .map(|embedding| Embedding::from(embedding.embedding)) - .collect()); - } - StatusCode::TOO_MANY_REQUESTS => { - rate_limiting = true; - let mut body = String::new(); - response.body_mut().read_to_string(&mut body).await?; - - let delay_duration = { - let delay = Duration::from_secs(BACKOFF_SECONDS[request_number - 1] as u64); - if let Some(time_to_reset) = - response.headers().get("x-ratelimit-reset-tokens") - { - if let Ok(time_str) = time_to_reset.to_str() { - parse(time_str).unwrap_or(delay) - } else { - delay - } - } else { - delay - } - }; - - // If we've previously rate limited, increment the duration but not the count - let reset_time = Instant::now().add(delay_duration); - self.update_reset_time(reset_time); - - log::trace!( - "openai rate limiting: waiting {:?} until lifted", - &delay_duration - ); - - self.executor.timer(delay_duration).await; - } - _ => { - let mut body = String::new(); - response.body_mut().read_to_string(&mut body).await?; - return Err(anyhow!( - "open ai bad request: {:?} {:?}", - &response.status(), - body - )); - } - } - } - Err(anyhow!("openai max retries")) - } -} - #[cfg(test)] mod tests { use super::*; diff --git a/crates/ai/src/models.rs b/crates/ai/src/models.rs index d0206cc41c..1db3d58c6f 100644 --- a/crates/ai/src/models.rs +++ b/crates/ai/src/models.rs @@ -1,66 +1,16 @@ -use anyhow::anyhow; -use tiktoken_rs::CoreBPE; -use util::ResultExt; +pub enum TruncationDirection { + Start, + End, +} pub trait LanguageModel { fn name(&self) -> String; fn count_tokens(&self, content: &str) -> anyhow::Result; - fn truncate(&self, content: &str, length: usize) -> anyhow::Result; - fn truncate_start(&self, content: &str, length: usize) -> anyhow::Result; + fn truncate( + &self, + content: &str, + length: usize, + direction: TruncationDirection, + ) -> anyhow::Result; fn capacity(&self) -> anyhow::Result; } - -pub struct OpenAILanguageModel { - name: String, - bpe: Option, -} - -impl OpenAILanguageModel { - pub fn load(model_name: &str) -> Self { - let bpe = tiktoken_rs::get_bpe_from_model(model_name).log_err(); - OpenAILanguageModel { - name: model_name.to_string(), - bpe, - } - } -} - -impl LanguageModel for OpenAILanguageModel { - fn name(&self) -> String { - self.name.clone() - } - fn count_tokens(&self, content: &str) -> anyhow::Result { - if let Some(bpe) = &self.bpe { - anyhow::Ok(bpe.encode_with_special_tokens(content).len()) - } else { - Err(anyhow!("bpe for open ai model was not retrieved")) - } - } - fn truncate(&self, content: &str, length: usize) -> anyhow::Result { - if let Some(bpe) = &self.bpe { - let tokens = bpe.encode_with_special_tokens(content); - if tokens.len() > length { - bpe.decode(tokens[..length].to_vec()) - } else { - bpe.decode(tokens) - } - } else { - Err(anyhow!("bpe for open ai model was not retrieved")) - } - } - fn truncate_start(&self, content: &str, length: usize) -> anyhow::Result { - if let Some(bpe) = &self.bpe { - let tokens = bpe.encode_with_special_tokens(content); - if tokens.len() > length { - bpe.decode(tokens[length..].to_vec()) - } else { - bpe.decode(tokens) - } - } else { - Err(anyhow!("bpe for open ai model was not retrieved")) - } - } - fn capacity(&self) -> anyhow::Result { - anyhow::Ok(tiktoken_rs::model::get_context_size(&self.name)) - } -} diff --git a/crates/ai/src/templates/base.rs b/crates/ai/src/prompts/base.rs similarity index 85% rename from crates/ai/src/templates/base.rs rename to crates/ai/src/prompts/base.rs index bda1d6c30e..75bad00154 100644 --- a/crates/ai/src/templates/base.rs +++ b/crates/ai/src/prompts/base.rs @@ -6,7 +6,7 @@ use language::BufferSnapshot; use util::ResultExt; use crate::models::LanguageModel; -use crate::templates::repository_context::PromptCodeSnippet; +use crate::prompts::repository_context::PromptCodeSnippet; pub(crate) enum PromptFileType { Text, @@ -125,6 +125,9 @@ impl PromptChain { #[cfg(test)] pub(crate) mod tests { + use crate::models::TruncationDirection; + use crate::test::FakeLanguageModel; + use super::*; #[test] @@ -141,7 +144,11 @@ pub(crate) mod tests { let mut token_count = args.model.count_tokens(&content)?; if let Some(max_token_length) = max_token_length { if token_count > max_token_length { - content = args.model.truncate(&content, max_token_length)?; + content = args.model.truncate( + &content, + max_token_length, + TruncationDirection::End, + )?; token_count = max_token_length; } } @@ -162,7 +169,11 @@ pub(crate) mod tests { let mut token_count = args.model.count_tokens(&content)?; if let Some(max_token_length) = max_token_length { if token_count > max_token_length { - content = args.model.truncate(&content, max_token_length)?; + content = args.model.truncate( + &content, + max_token_length, + TruncationDirection::End, + )?; token_count = max_token_length; } } @@ -171,38 +182,7 @@ pub(crate) mod tests { } } - #[derive(Clone)] - struct DummyLanguageModel { - capacity: usize, - } - - impl LanguageModel for DummyLanguageModel { - fn name(&self) -> String { - "dummy".to_string() - } - fn count_tokens(&self, content: &str) -> anyhow::Result { - anyhow::Ok(content.chars().collect::>().len()) - } - fn truncate(&self, content: &str, length: usize) -> anyhow::Result { - anyhow::Ok( - content.chars().collect::>()[..length] - .into_iter() - .collect::(), - ) - } - fn truncate_start(&self, content: &str, length: usize) -> anyhow::Result { - anyhow::Ok( - content.chars().collect::>()[length..] - .into_iter() - .collect::(), - ) - } - fn capacity(&self) -> anyhow::Result { - anyhow::Ok(self.capacity) - } - } - - let model: Arc = Arc::new(DummyLanguageModel { capacity: 100 }); + let model: Arc = Arc::new(FakeLanguageModel { capacity: 100 }); let args = PromptArguments { model: model.clone(), language_name: None, @@ -238,7 +218,7 @@ pub(crate) mod tests { // Testing with Truncation Off // Should ignore capacity and return all prompts - let model: Arc = Arc::new(DummyLanguageModel { capacity: 20 }); + let model: Arc = Arc::new(FakeLanguageModel { capacity: 20 }); let args = PromptArguments { model: model.clone(), language_name: None, @@ -275,7 +255,7 @@ pub(crate) mod tests { // Testing with Truncation Off // Should ignore capacity and return all prompts let capacity = 20; - let model: Arc = Arc::new(DummyLanguageModel { capacity }); + let model: Arc = Arc::new(FakeLanguageModel { capacity }); let args = PromptArguments { model: model.clone(), language_name: None, @@ -311,7 +291,7 @@ pub(crate) mod tests { // Change Ordering of Prompts Based on Priority let capacity = 120; let reserved_tokens = 10; - let model: Arc = Arc::new(DummyLanguageModel { capacity }); + let model: Arc = Arc::new(FakeLanguageModel { capacity }); let args = PromptArguments { model: model.clone(), language_name: None, diff --git a/crates/ai/src/templates/file_context.rs b/crates/ai/src/prompts/file_context.rs similarity index 91% rename from crates/ai/src/templates/file_context.rs rename to crates/ai/src/prompts/file_context.rs index 1afd61192e..f108a62f6f 100644 --- a/crates/ai/src/templates/file_context.rs +++ b/crates/ai/src/prompts/file_context.rs @@ -3,8 +3,9 @@ use language::BufferSnapshot; use language::ToOffset; use crate::models::LanguageModel; -use crate::templates::base::PromptArguments; -use crate::templates::base::PromptTemplate; +use crate::models::TruncationDirection; +use crate::prompts::base::PromptArguments; +use crate::prompts::base::PromptTemplate; use std::fmt::Write; use std::ops::Range; use std::sync::Arc; @@ -70,8 +71,9 @@ fn retrieve_context( }; let truncated_start_window = - model.truncate_start(&start_window, start_goal_tokens)?; - let truncated_end_window = model.truncate(&end_window, end_goal_tokens)?; + model.truncate(&start_window, start_goal_tokens, TruncationDirection::Start)?; + let truncated_end_window = + model.truncate(&end_window, end_goal_tokens, TruncationDirection::End)?; writeln!( prompt, "{truncated_start_window}{selected_window}{truncated_end_window}" @@ -89,7 +91,7 @@ fn retrieve_context( if let Some(max_token_count) = max_token_count { if model.count_tokens(&prompt)? > max_token_count { truncated = true; - prompt = model.truncate(&prompt, max_token_count)?; + prompt = model.truncate(&prompt, max_token_count, TruncationDirection::End)?; } } } @@ -148,7 +150,9 @@ impl PromptTemplate for FileContext { // Really dumb truncation strategy if let Some(max_tokens) = max_token_length { - prompt = args.model.truncate(&prompt, max_tokens)?; + prompt = args + .model + .truncate(&prompt, max_tokens, TruncationDirection::End)?; } let token_count = args.model.count_tokens(&prompt)?; diff --git a/crates/ai/src/templates/generate.rs b/crates/ai/src/prompts/generate.rs similarity index 92% rename from crates/ai/src/templates/generate.rs rename to crates/ai/src/prompts/generate.rs index 1eeb197f93..c7be620107 100644 --- a/crates/ai/src/templates/generate.rs +++ b/crates/ai/src/prompts/generate.rs @@ -1,4 +1,4 @@ -use crate::templates::base::{PromptArguments, PromptFileType, PromptTemplate}; +use crate::prompts::base::{PromptArguments, PromptFileType, PromptTemplate}; use anyhow::anyhow; use std::fmt::Write; @@ -85,7 +85,11 @@ impl PromptTemplate for GenerateInlineContent { // Really dumb truncation strategy if let Some(max_tokens) = max_token_length { - prompt = args.model.truncate(&prompt, max_tokens)?; + prompt = args.model.truncate( + &prompt, + max_tokens, + crate::models::TruncationDirection::End, + )?; } let token_count = args.model.count_tokens(&prompt)?; diff --git a/crates/ai/src/templates/mod.rs b/crates/ai/src/prompts/mod.rs similarity index 100% rename from crates/ai/src/templates/mod.rs rename to crates/ai/src/prompts/mod.rs diff --git a/crates/ai/src/templates/preamble.rs b/crates/ai/src/prompts/preamble.rs similarity index 95% rename from crates/ai/src/templates/preamble.rs rename to crates/ai/src/prompts/preamble.rs index 9eabaaeb97..92e0edeb78 100644 --- a/crates/ai/src/templates/preamble.rs +++ b/crates/ai/src/prompts/preamble.rs @@ -1,4 +1,4 @@ -use crate::templates::base::{PromptArguments, PromptFileType, PromptTemplate}; +use crate::prompts::base::{PromptArguments, PromptFileType, PromptTemplate}; use std::fmt::Write; pub struct EngineerPreamble {} diff --git a/crates/ai/src/templates/repository_context.rs b/crates/ai/src/prompts/repository_context.rs similarity index 98% rename from crates/ai/src/templates/repository_context.rs rename to crates/ai/src/prompts/repository_context.rs index a8e7f4b5af..c21b0f995c 100644 --- a/crates/ai/src/templates/repository_context.rs +++ b/crates/ai/src/prompts/repository_context.rs @@ -1,4 +1,4 @@ -use crate::templates::base::{PromptArguments, PromptTemplate}; +use crate::prompts::base::{PromptArguments, PromptTemplate}; use std::fmt::Write; use std::{ops::Range, path::PathBuf}; diff --git a/crates/ai/src/providers/mod.rs b/crates/ai/src/providers/mod.rs new file mode 100644 index 0000000000..acd0f9d910 --- /dev/null +++ b/crates/ai/src/providers/mod.rs @@ -0,0 +1 @@ +pub mod open_ai; diff --git a/crates/ai/src/providers/open_ai/completion.rs b/crates/ai/src/providers/open_ai/completion.rs new file mode 100644 index 0000000000..94685fd233 --- /dev/null +++ b/crates/ai/src/providers/open_ai/completion.rs @@ -0,0 +1,298 @@ +use anyhow::{anyhow, Result}; +use futures::{ + future::BoxFuture, io::BufReader, stream::BoxStream, AsyncBufReadExt, AsyncReadExt, FutureExt, + Stream, StreamExt, +}; +use gpui::{executor::Background, AppContext}; +use isahc::{http::StatusCode, Request, RequestExt}; +use parking_lot::RwLock; +use serde::{Deserialize, Serialize}; +use std::{ + env, + fmt::{self, Display}, + io, + sync::Arc, +}; +use util::ResultExt; + +use crate::{ + auth::{CredentialProvider, ProviderCredential}, + completion::{CompletionProvider, CompletionRequest}, + models::LanguageModel, +}; + +use crate::providers::open_ai::{OpenAILanguageModel, OPENAI_API_URL}; + +#[derive(Clone, Copy, Serialize, Deserialize, Debug, Eq, PartialEq)] +#[serde(rename_all = "lowercase")] +pub enum Role { + User, + Assistant, + System, +} + +impl Role { + pub fn cycle(&mut self) { + *self = match self { + Role::User => Role::Assistant, + Role::Assistant => Role::System, + Role::System => Role::User, + } + } +} + +impl Display for Role { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Role::User => write!(f, "User"), + Role::Assistant => write!(f, "Assistant"), + Role::System => write!(f, "System"), + } + } +} + +#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)] +pub struct RequestMessage { + pub role: Role, + pub content: String, +} + +#[derive(Debug, Default, Serialize)] +pub struct OpenAIRequest { + pub model: String, + pub messages: Vec, + pub stream: bool, + pub stop: Vec, + pub temperature: f32, +} + +impl CompletionRequest for OpenAIRequest { + fn data(&self) -> serde_json::Result { + serde_json::to_string(self) + } +} + +#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)] +pub struct ResponseMessage { + pub role: Option, + pub content: Option, +} + +#[derive(Deserialize, Debug)] +pub struct OpenAIUsage { + pub prompt_tokens: u32, + pub completion_tokens: u32, + pub total_tokens: u32, +} + +#[derive(Deserialize, Debug)] +pub struct ChatChoiceDelta { + pub index: u32, + pub delta: ResponseMessage, + pub finish_reason: Option, +} + +#[derive(Deserialize, Debug)] +pub struct OpenAIResponseStreamEvent { + pub id: Option, + pub object: String, + pub created: u32, + pub model: String, + pub choices: Vec, + pub usage: Option, +} + +pub async fn stream_completion( + credential: ProviderCredential, + executor: Arc, + request: Box, +) -> Result>> { + let api_key = match credential { + ProviderCredential::Credentials { api_key } => api_key, + _ => { + return Err(anyhow!("no credentials provider for completion")); + } + }; + + let (tx, rx) = futures::channel::mpsc::unbounded::>(); + + let json_data = request.data()?; + let mut response = Request::post(format!("{OPENAI_API_URL}/chat/completions")) + .header("Content-Type", "application/json") + .header("Authorization", format!("Bearer {}", api_key)) + .body(json_data)? + .send_async() + .await?; + + let status = response.status(); + if status == StatusCode::OK { + executor + .spawn(async move { + let mut lines = BufReader::new(response.body_mut()).lines(); + + fn parse_line( + line: Result, + ) -> Result> { + if let Some(data) = line?.strip_prefix("data: ") { + let event = serde_json::from_str(&data)?; + Ok(Some(event)) + } else { + Ok(None) + } + } + + while let Some(line) = lines.next().await { + if let Some(event) = parse_line(line).transpose() { + let done = event.as_ref().map_or(false, |event| { + event + .choices + .last() + .map_or(false, |choice| choice.finish_reason.is_some()) + }); + if tx.unbounded_send(event).is_err() { + break; + } + + if done { + break; + } + } + } + + anyhow::Ok(()) + }) + .detach(); + + Ok(rx) + } else { + let mut body = String::new(); + response.body_mut().read_to_string(&mut body).await?; + + #[derive(Deserialize)] + struct OpenAIResponse { + error: OpenAIError, + } + + #[derive(Deserialize)] + struct OpenAIError { + message: String, + } + + match serde_json::from_str::(&body) { + Ok(response) if !response.error.message.is_empty() => Err(anyhow!( + "Failed to connect to OpenAI API: {}", + response.error.message, + )), + + _ => Err(anyhow!( + "Failed to connect to OpenAI API: {} {}", + response.status(), + body, + )), + } + } +} + +#[derive(Clone)] +pub struct OpenAICompletionProvider { + model: OpenAILanguageModel, + credential: Arc>, + executor: Arc, +} + +impl OpenAICompletionProvider { + pub fn new(model_name: &str, executor: Arc) -> Self { + let model = OpenAILanguageModel::load(model_name); + let credential = Arc::new(RwLock::new(ProviderCredential::NoCredentials)); + Self { + model, + credential, + executor, + } + } +} + +impl CredentialProvider for OpenAICompletionProvider { + fn has_credentials(&self) -> bool { + match *self.credential.read() { + ProviderCredential::Credentials { .. } => true, + _ => false, + } + } + fn retrieve_credentials(&self, cx: &AppContext) -> ProviderCredential { + let mut credential = self.credential.write(); + match *credential { + ProviderCredential::Credentials { .. } => { + return credential.clone(); + } + _ => { + if let Ok(api_key) = env::var("OPENAI_API_KEY") { + *credential = ProviderCredential::Credentials { api_key }; + } else if let Some((_, api_key)) = cx + .platform() + .read_credentials(OPENAI_API_URL) + .log_err() + .flatten() + { + if let Some(api_key) = String::from_utf8(api_key).log_err() { + *credential = ProviderCredential::Credentials { api_key }; + } + } else { + }; + } + } + + credential.clone() + } + + fn save_credentials(&self, cx: &AppContext, credential: ProviderCredential) { + match credential.clone() { + ProviderCredential::Credentials { api_key } => { + cx.platform() + .write_credentials(OPENAI_API_URL, "Bearer", api_key.as_bytes()) + .log_err(); + } + _ => {} + } + + *self.credential.write() = credential; + } + fn delete_credentials(&self, cx: &AppContext) { + cx.platform().delete_credentials(OPENAI_API_URL).log_err(); + *self.credential.write() = ProviderCredential::NoCredentials; + } +} + +impl CompletionProvider for OpenAICompletionProvider { + fn base_model(&self) -> Box { + let model: Box = Box::new(self.model.clone()); + model + } + fn complete( + &self, + prompt: Box, + ) -> BoxFuture<'static, Result>>> { + // Currently the CompletionRequest for OpenAI, includes a 'model' parameter + // This means that the model is determined by the CompletionRequest and not the CompletionProvider, + // which is currently model based, due to the langauge model. + // At some point in the future we should rectify this. + let credential = self.credential.read().clone(); + let request = stream_completion(credential, self.executor.clone(), prompt); + async move { + let response = request.await?; + let stream = response + .filter_map(|response| async move { + match response { + Ok(mut response) => Some(Ok(response.choices.pop()?.delta.content?)), + Err(error) => Some(Err(error)), + } + }) + .boxed(); + Ok(stream) + } + .boxed() + } + fn box_clone(&self) -> Box { + Box::new((*self).clone()) + } +} diff --git a/crates/ai/src/providers/open_ai/embedding.rs b/crates/ai/src/providers/open_ai/embedding.rs new file mode 100644 index 0000000000..fbfd0028f9 --- /dev/null +++ b/crates/ai/src/providers/open_ai/embedding.rs @@ -0,0 +1,306 @@ +use anyhow::{anyhow, Result}; +use async_trait::async_trait; +use futures::AsyncReadExt; +use gpui::executor::Background; +use gpui::{serde_json, AppContext}; +use isahc::http::StatusCode; +use isahc::prelude::Configurable; +use isahc::{AsyncBody, Response}; +use lazy_static::lazy_static; +use parking_lot::{Mutex, RwLock}; +use parse_duration::parse; +use postage::watch; +use serde::{Deserialize, Serialize}; +use std::env; +use std::ops::Add; +use std::sync::Arc; +use std::time::{Duration, Instant}; +use tiktoken_rs::{cl100k_base, CoreBPE}; +use util::http::{HttpClient, Request}; +use util::ResultExt; + +use crate::auth::{CredentialProvider, ProviderCredential}; +use crate::embedding::{Embedding, EmbeddingProvider}; +use crate::models::LanguageModel; +use crate::providers::open_ai::OpenAILanguageModel; + +use crate::providers::open_ai::OPENAI_API_URL; + +lazy_static! { + static ref OPENAI_BPE_TOKENIZER: CoreBPE = cl100k_base().unwrap(); +} + +#[derive(Clone)] +pub struct OpenAIEmbeddingProvider { + model: OpenAILanguageModel, + credential: Arc>, + pub client: Arc, + pub executor: Arc, + rate_limit_count_rx: watch::Receiver>, + rate_limit_count_tx: Arc>>>, +} + +#[derive(Serialize)] +struct OpenAIEmbeddingRequest<'a> { + model: &'static str, + input: Vec<&'a str>, +} + +#[derive(Deserialize)] +struct OpenAIEmbeddingResponse { + data: Vec, + usage: OpenAIEmbeddingUsage, +} + +#[derive(Debug, Deserialize)] +struct OpenAIEmbedding { + embedding: Vec, + index: usize, + object: String, +} + +#[derive(Deserialize)] +struct OpenAIEmbeddingUsage { + prompt_tokens: usize, + total_tokens: usize, +} + +impl OpenAIEmbeddingProvider { + pub fn new(client: Arc, executor: Arc) -> Self { + let (rate_limit_count_tx, rate_limit_count_rx) = watch::channel_with(None); + let rate_limit_count_tx = Arc::new(Mutex::new(rate_limit_count_tx)); + + let model = OpenAILanguageModel::load("text-embedding-ada-002"); + let credential = Arc::new(RwLock::new(ProviderCredential::NoCredentials)); + + OpenAIEmbeddingProvider { + model, + credential, + client, + executor, + rate_limit_count_rx, + rate_limit_count_tx, + } + } + + fn get_api_key(&self) -> Result { + match self.credential.read().clone() { + ProviderCredential::Credentials { api_key } => Ok(api_key), + _ => Err(anyhow!("api credentials not provided")), + } + } + + fn resolve_rate_limit(&self) { + let reset_time = *self.rate_limit_count_tx.lock().borrow(); + + if let Some(reset_time) = reset_time { + if Instant::now() >= reset_time { + *self.rate_limit_count_tx.lock().borrow_mut() = None + } + } + + log::trace!( + "resolving reset time: {:?}", + *self.rate_limit_count_tx.lock().borrow() + ); + } + + fn update_reset_time(&self, reset_time: Instant) { + let original_time = *self.rate_limit_count_tx.lock().borrow(); + + let updated_time = if let Some(original_time) = original_time { + if reset_time < original_time { + Some(reset_time) + } else { + Some(original_time) + } + } else { + Some(reset_time) + }; + + log::trace!("updating rate limit time: {:?}", updated_time); + + *self.rate_limit_count_tx.lock().borrow_mut() = updated_time; + } + async fn send_request( + &self, + api_key: &str, + spans: Vec<&str>, + request_timeout: u64, + ) -> Result> { + let request = Request::post("https://api.openai.com/v1/embeddings") + .redirect_policy(isahc::config::RedirectPolicy::Follow) + .timeout(Duration::from_secs(request_timeout)) + .header("Content-Type", "application/json") + .header("Authorization", format!("Bearer {}", api_key)) + .body( + serde_json::to_string(&OpenAIEmbeddingRequest { + input: spans.clone(), + model: "text-embedding-ada-002", + }) + .unwrap() + .into(), + )?; + + Ok(self.client.send(request).await?) + } +} + +impl CredentialProvider for OpenAIEmbeddingProvider { + fn has_credentials(&self) -> bool { + match *self.credential.read() { + ProviderCredential::Credentials { .. } => true, + _ => false, + } + } + fn retrieve_credentials(&self, cx: &AppContext) -> ProviderCredential { + let mut credential = self.credential.write(); + match *credential { + ProviderCredential::Credentials { .. } => { + return credential.clone(); + } + _ => { + if let Ok(api_key) = env::var("OPENAI_API_KEY") { + *credential = ProviderCredential::Credentials { api_key }; + } else if let Some((_, api_key)) = cx + .platform() + .read_credentials(OPENAI_API_URL) + .log_err() + .flatten() + { + if let Some(api_key) = String::from_utf8(api_key).log_err() { + *credential = ProviderCredential::Credentials { api_key }; + } + } else { + }; + } + } + + credential.clone() + } + + fn save_credentials(&self, cx: &AppContext, credential: ProviderCredential) { + match credential.clone() { + ProviderCredential::Credentials { api_key } => { + cx.platform() + .write_credentials(OPENAI_API_URL, "Bearer", api_key.as_bytes()) + .log_err(); + } + _ => {} + } + + *self.credential.write() = credential; + } + fn delete_credentials(&self, cx: &AppContext) { + cx.platform().delete_credentials(OPENAI_API_URL).log_err(); + *self.credential.write() = ProviderCredential::NoCredentials; + } +} + +#[async_trait] +impl EmbeddingProvider for OpenAIEmbeddingProvider { + fn base_model(&self) -> Box { + let model: Box = Box::new(self.model.clone()); + model + } + + fn max_tokens_per_batch(&self) -> usize { + 50000 + } + + fn rate_limit_expiration(&self) -> Option { + *self.rate_limit_count_rx.borrow() + } + + async fn embed_batch(&self, spans: Vec) -> Result> { + const BACKOFF_SECONDS: [usize; 4] = [3, 5, 15, 45]; + const MAX_RETRIES: usize = 4; + + let api_key = self.get_api_key()?; + + let mut request_number = 0; + let mut rate_limiting = false; + let mut request_timeout: u64 = 15; + let mut response: Response; + while request_number < MAX_RETRIES { + response = self + .send_request( + &api_key, + spans.iter().map(|x| &**x).collect(), + request_timeout, + ) + .await?; + + request_number += 1; + + match response.status() { + StatusCode::REQUEST_TIMEOUT => { + request_timeout += 5; + } + StatusCode::OK => { + let mut body = String::new(); + response.body_mut().read_to_string(&mut body).await?; + let response: OpenAIEmbeddingResponse = serde_json::from_str(&body)?; + + log::trace!( + "openai embedding completed. tokens: {:?}", + response.usage.total_tokens + ); + + // If we complete a request successfully that was previously rate_limited + // resolve the rate limit + if rate_limiting { + self.resolve_rate_limit() + } + + return Ok(response + .data + .into_iter() + .map(|embedding| Embedding::from(embedding.embedding)) + .collect()); + } + StatusCode::TOO_MANY_REQUESTS => { + rate_limiting = true; + let mut body = String::new(); + response.body_mut().read_to_string(&mut body).await?; + + let delay_duration = { + let delay = Duration::from_secs(BACKOFF_SECONDS[request_number - 1] as u64); + if let Some(time_to_reset) = + response.headers().get("x-ratelimit-reset-tokens") + { + if let Ok(time_str) = time_to_reset.to_str() { + parse(time_str).unwrap_or(delay) + } else { + delay + } + } else { + delay + } + }; + + // If we've previously rate limited, increment the duration but not the count + let reset_time = Instant::now().add(delay_duration); + self.update_reset_time(reset_time); + + log::trace!( + "openai rate limiting: waiting {:?} until lifted", + &delay_duration + ); + + self.executor.timer(delay_duration).await; + } + _ => { + let mut body = String::new(); + response.body_mut().read_to_string(&mut body).await?; + return Err(anyhow!( + "open ai bad request: {:?} {:?}", + &response.status(), + body + )); + } + } + } + Err(anyhow!("openai max retries")) + } +} diff --git a/crates/ai/src/providers/open_ai/mod.rs b/crates/ai/src/providers/open_ai/mod.rs new file mode 100644 index 0000000000..7d2f86045d --- /dev/null +++ b/crates/ai/src/providers/open_ai/mod.rs @@ -0,0 +1,9 @@ +pub mod completion; +pub mod embedding; +pub mod model; + +pub use completion::*; +pub use embedding::*; +pub use model::OpenAILanguageModel; + +pub const OPENAI_API_URL: &'static str = "https://api.openai.com/v1"; diff --git a/crates/ai/src/providers/open_ai/model.rs b/crates/ai/src/providers/open_ai/model.rs new file mode 100644 index 0000000000..6e306c80b9 --- /dev/null +++ b/crates/ai/src/providers/open_ai/model.rs @@ -0,0 +1,57 @@ +use anyhow::anyhow; +use tiktoken_rs::CoreBPE; +use util::ResultExt; + +use crate::models::{LanguageModel, TruncationDirection}; + +#[derive(Clone)] +pub struct OpenAILanguageModel { + name: String, + bpe: Option, +} + +impl OpenAILanguageModel { + pub fn load(model_name: &str) -> Self { + let bpe = tiktoken_rs::get_bpe_from_model(model_name).log_err(); + OpenAILanguageModel { + name: model_name.to_string(), + bpe, + } + } +} + +impl LanguageModel for OpenAILanguageModel { + fn name(&self) -> String { + self.name.clone() + } + fn count_tokens(&self, content: &str) -> anyhow::Result { + if let Some(bpe) = &self.bpe { + anyhow::Ok(bpe.encode_with_special_tokens(content).len()) + } else { + Err(anyhow!("bpe for open ai model was not retrieved")) + } + } + fn truncate( + &self, + content: &str, + length: usize, + direction: TruncationDirection, + ) -> anyhow::Result { + if let Some(bpe) = &self.bpe { + let tokens = bpe.encode_with_special_tokens(content); + if tokens.len() > length { + match direction { + TruncationDirection::End => bpe.decode(tokens[..length].to_vec()), + TruncationDirection::Start => bpe.decode(tokens[length..].to_vec()), + } + } else { + bpe.decode(tokens) + } + } else { + Err(anyhow!("bpe for open ai model was not retrieved")) + } + } + fn capacity(&self) -> anyhow::Result { + anyhow::Ok(tiktoken_rs::model::get_context_size(&self.name)) + } +} diff --git a/crates/ai/src/providers/open_ai/new.rs b/crates/ai/src/providers/open_ai/new.rs new file mode 100644 index 0000000000..c7d67f2ba1 --- /dev/null +++ b/crates/ai/src/providers/open_ai/new.rs @@ -0,0 +1,11 @@ +pub trait LanguageModel { + fn name(&self) -> String; + fn count_tokens(&self, content: &str) -> anyhow::Result; + fn truncate( + &self, + content: &str, + length: usize, + direction: TruncationDirection, + ) -> anyhow::Result; + fn capacity(&self) -> anyhow::Result; +} diff --git a/crates/ai/src/test.rs b/crates/ai/src/test.rs new file mode 100644 index 0000000000..d4165f3cca --- /dev/null +++ b/crates/ai/src/test.rs @@ -0,0 +1,191 @@ +use std::{ + sync::atomic::{self, AtomicUsize, Ordering}, + time::Instant, +}; + +use async_trait::async_trait; +use futures::{channel::mpsc, future::BoxFuture, stream::BoxStream, FutureExt, StreamExt}; +use gpui::AppContext; +use parking_lot::Mutex; + +use crate::{ + auth::{CredentialProvider, ProviderCredential}, + completion::{CompletionProvider, CompletionRequest}, + embedding::{Embedding, EmbeddingProvider}, + models::{LanguageModel, TruncationDirection}, +}; + +#[derive(Clone)] +pub struct FakeLanguageModel { + pub capacity: usize, +} + +impl LanguageModel for FakeLanguageModel { + fn name(&self) -> String { + "dummy".to_string() + } + fn count_tokens(&self, content: &str) -> anyhow::Result { + anyhow::Ok(content.chars().collect::>().len()) + } + fn truncate( + &self, + content: &str, + length: usize, + direction: TruncationDirection, + ) -> anyhow::Result { + println!("TRYING TO TRUNCATE: {:?}", length.clone()); + + if length > self.count_tokens(content)? { + println!("NOT TRUNCATING"); + return anyhow::Ok(content.to_string()); + } + + anyhow::Ok(match direction { + TruncationDirection::End => content.chars().collect::>()[..length] + .into_iter() + .collect::(), + TruncationDirection::Start => content.chars().collect::>()[length..] + .into_iter() + .collect::(), + }) + } + fn capacity(&self) -> anyhow::Result { + anyhow::Ok(self.capacity) + } +} + +pub struct FakeEmbeddingProvider { + pub embedding_count: AtomicUsize, +} + +impl Clone for FakeEmbeddingProvider { + fn clone(&self) -> Self { + FakeEmbeddingProvider { + embedding_count: AtomicUsize::new(self.embedding_count.load(Ordering::SeqCst)), + } + } +} + +impl Default for FakeEmbeddingProvider { + fn default() -> Self { + FakeEmbeddingProvider { + embedding_count: AtomicUsize::default(), + } + } +} + +impl FakeEmbeddingProvider { + pub fn embedding_count(&self) -> usize { + self.embedding_count.load(atomic::Ordering::SeqCst) + } + + pub fn embed_sync(&self, span: &str) -> Embedding { + let mut result = vec![1.0; 26]; + for letter in span.chars() { + let letter = letter.to_ascii_lowercase(); + if letter as u32 >= 'a' as u32 { + let ix = (letter as u32) - ('a' as u32); + if ix < 26 { + result[ix as usize] += 1.0; + } + } + } + + let norm = result.iter().map(|x| x * x).sum::().sqrt(); + for x in &mut result { + *x /= norm; + } + + result.into() + } +} + +impl CredentialProvider for FakeEmbeddingProvider { + fn has_credentials(&self) -> bool { + true + } + fn retrieve_credentials(&self, _cx: &AppContext) -> ProviderCredential { + ProviderCredential::NotNeeded + } + fn save_credentials(&self, _cx: &AppContext, _credential: ProviderCredential) {} + fn delete_credentials(&self, _cx: &AppContext) {} +} + +#[async_trait] +impl EmbeddingProvider for FakeEmbeddingProvider { + fn base_model(&self) -> Box { + Box::new(FakeLanguageModel { capacity: 1000 }) + } + fn max_tokens_per_batch(&self) -> usize { + 1000 + } + + fn rate_limit_expiration(&self) -> Option { + None + } + + async fn embed_batch(&self, spans: Vec) -> anyhow::Result> { + self.embedding_count + .fetch_add(spans.len(), atomic::Ordering::SeqCst); + + anyhow::Ok(spans.iter().map(|span| self.embed_sync(span)).collect()) + } +} + +pub struct FakeCompletionProvider { + last_completion_tx: Mutex>>, +} + +impl Clone for FakeCompletionProvider { + fn clone(&self) -> Self { + Self { + last_completion_tx: Mutex::new(None), + } + } +} + +impl FakeCompletionProvider { + pub fn new() -> Self { + Self { + last_completion_tx: Mutex::new(None), + } + } + + pub fn send_completion(&self, completion: impl Into) { + let mut tx = self.last_completion_tx.lock(); + tx.as_mut().unwrap().try_send(completion.into()).unwrap(); + } + + pub fn finish_completion(&self) { + self.last_completion_tx.lock().take().unwrap(); + } +} + +impl CredentialProvider for FakeCompletionProvider { + fn has_credentials(&self) -> bool { + true + } + fn retrieve_credentials(&self, _cx: &AppContext) -> ProviderCredential { + ProviderCredential::NotNeeded + } + fn save_credentials(&self, _cx: &AppContext, _credential: ProviderCredential) {} + fn delete_credentials(&self, _cx: &AppContext) {} +} + +impl CompletionProvider for FakeCompletionProvider { + fn base_model(&self) -> Box { + let model: Box = Box::new(FakeLanguageModel { capacity: 8190 }); + model + } + fn complete( + &self, + _prompt: Box, + ) -> BoxFuture<'static, anyhow::Result>>> { + let (tx, rx) = mpsc::channel(1); + *self.last_completion_tx.lock() = Some(tx); + async move { Ok(rx.map(|rx| Ok(rx)).boxed()) }.boxed() + } + fn box_clone(&self) -> Box { + Box::new((*self).clone()) + } +} diff --git a/crates/ai2/Cargo.toml b/crates/ai2/Cargo.toml new file mode 100644 index 0000000000..4f06840e8e --- /dev/null +++ b/crates/ai2/Cargo.toml @@ -0,0 +1,38 @@ +[package] +name = "ai2" +version = "0.1.0" +edition = "2021" +publish = false + +[lib] +path = "src/ai2.rs" +doctest = false + +[features] +test-support = [] + +[dependencies] +gpui2 = { path = "../gpui2" } +util = { path = "../util" } +language2 = { path = "../language2" } +async-trait.workspace = true +anyhow.workspace = true +futures.workspace = true +lazy_static.workspace = true +ordered-float.workspace = true +parking_lot.workspace = true +isahc.workspace = true +regex.workspace = true +serde.workspace = true +serde_json.workspace = true +postage.workspace = true +rand.workspace = true +log.workspace = true +parse_duration = "2.1.1" +tiktoken-rs = "0.5.0" +matrixmultiply = "0.3.7" +rusqlite = { version = "0.29.0", features = ["blob", "array", "modern_sqlite"] } +bincode = "1.3.3" + +[dev-dependencies] +gpui2 = { path = "../gpui2", features = ["test-support"] } diff --git a/crates/ai2/src/ai2.rs b/crates/ai2/src/ai2.rs new file mode 100644 index 0000000000..dda22d2a1d --- /dev/null +++ b/crates/ai2/src/ai2.rs @@ -0,0 +1,8 @@ +pub mod auth; +pub mod completion; +pub mod embedding; +pub mod models; +pub mod prompts; +pub mod providers; +#[cfg(any(test, feature = "test-support"))] +pub mod test; diff --git a/crates/ai2/src/auth.rs b/crates/ai2/src/auth.rs new file mode 100644 index 0000000000..e4670bb449 --- /dev/null +++ b/crates/ai2/src/auth.rs @@ -0,0 +1,17 @@ +use async_trait::async_trait; +use gpui2::AppContext; + +#[derive(Clone, Debug)] +pub enum ProviderCredential { + Credentials { api_key: String }, + NoCredentials, + NotNeeded, +} + +#[async_trait] +pub trait CredentialProvider: Send + Sync { + fn has_credentials(&self) -> bool; + async fn retrieve_credentials(&self, cx: &mut AppContext) -> ProviderCredential; + async fn save_credentials(&self, cx: &mut AppContext, credential: ProviderCredential); + async fn delete_credentials(&self, cx: &mut AppContext); +} diff --git a/crates/ai2/src/completion.rs b/crates/ai2/src/completion.rs new file mode 100644 index 0000000000..30a60fcf1d --- /dev/null +++ b/crates/ai2/src/completion.rs @@ -0,0 +1,23 @@ +use anyhow::Result; +use futures::{future::BoxFuture, stream::BoxStream}; + +use crate::{auth::CredentialProvider, models::LanguageModel}; + +pub trait CompletionRequest: Send + Sync { + fn data(&self) -> serde_json::Result; +} + +pub trait CompletionProvider: CredentialProvider { + fn base_model(&self) -> Box; + fn complete( + &self, + prompt: Box, + ) -> BoxFuture<'static, Result>>>; + fn box_clone(&self) -> Box; +} + +impl Clone for Box { + fn clone(&self) -> Box { + self.box_clone() + } +} diff --git a/crates/ai2/src/embedding.rs b/crates/ai2/src/embedding.rs new file mode 100644 index 0000000000..7ea4786178 --- /dev/null +++ b/crates/ai2/src/embedding.rs @@ -0,0 +1,123 @@ +use std::time::Instant; + +use anyhow::Result; +use async_trait::async_trait; +use ordered_float::OrderedFloat; +use rusqlite::types::{FromSql, FromSqlResult, ToSqlOutput, ValueRef}; +use rusqlite::ToSql; + +use crate::auth::CredentialProvider; +use crate::models::LanguageModel; + +#[derive(Debug, PartialEq, Clone)] +pub struct Embedding(pub Vec); + +// This is needed for semantic index functionality +// Unfortunately it has to live wherever the "Embedding" struct is created. +// Keeping this in here though, introduces a 'rusqlite' dependency into AI +// which is less than ideal +impl FromSql for Embedding { + fn column_result(value: ValueRef) -> FromSqlResult { + let bytes = value.as_blob()?; + let embedding: Result, Box> = bincode::deserialize(bytes); + if embedding.is_err() { + return Err(rusqlite::types::FromSqlError::Other(embedding.unwrap_err())); + } + Ok(Embedding(embedding.unwrap())) + } +} + +impl ToSql for Embedding { + fn to_sql(&self) -> rusqlite::Result { + let bytes = bincode::serialize(&self.0) + .map_err(|err| rusqlite::Error::ToSqlConversionFailure(Box::new(err)))?; + Ok(ToSqlOutput::Owned(rusqlite::types::Value::Blob(bytes))) + } +} +impl From> for Embedding { + fn from(value: Vec) -> Self { + Embedding(value) + } +} + +impl Embedding { + pub fn similarity(&self, other: &Self) -> OrderedFloat { + let len = self.0.len(); + assert_eq!(len, other.0.len()); + + let mut result = 0.0; + unsafe { + matrixmultiply::sgemm( + 1, + len, + 1, + 1.0, + self.0.as_ptr(), + len as isize, + 1, + other.0.as_ptr(), + 1, + len as isize, + 0.0, + &mut result as *mut f32, + 1, + 1, + ); + } + OrderedFloat(result) + } +} + +#[async_trait] +pub trait EmbeddingProvider: CredentialProvider { + fn base_model(&self) -> Box; + async fn embed_batch(&self, spans: Vec) -> Result>; + fn max_tokens_per_batch(&self) -> usize; + fn rate_limit_expiration(&self) -> Option; +} + +#[cfg(test)] +mod tests { + use super::*; + use rand::prelude::*; + + #[gpui2::test] + fn test_similarity(mut rng: StdRng) { + assert_eq!( + Embedding::from(vec![1., 0., 0., 0., 0.]) + .similarity(&Embedding::from(vec![0., 1., 0., 0., 0.])), + 0. + ); + assert_eq!( + Embedding::from(vec![2., 0., 0., 0., 0.]) + .similarity(&Embedding::from(vec![3., 1., 0., 0., 0.])), + 6. + ); + + for _ in 0..100 { + let size = 1536; + let mut a = vec![0.; size]; + let mut b = vec![0.; size]; + for (a, b) in a.iter_mut().zip(b.iter_mut()) { + *a = rng.gen(); + *b = rng.gen(); + } + let a = Embedding::from(a); + let b = Embedding::from(b); + + assert_eq!( + round_to_decimals(a.similarity(&b), 1), + round_to_decimals(reference_dot(&a.0, &b.0), 1) + ); + } + + fn round_to_decimals(n: OrderedFloat, decimal_places: i32) -> f32 { + let factor = (10.0 as f32).powi(decimal_places); + (n * factor).round() / factor + } + + fn reference_dot(a: &[f32], b: &[f32]) -> OrderedFloat { + OrderedFloat(a.iter().zip(b.iter()).map(|(a, b)| a * b).sum()) + } + } +} diff --git a/crates/ai2/src/models.rs b/crates/ai2/src/models.rs new file mode 100644 index 0000000000..1db3d58c6f --- /dev/null +++ b/crates/ai2/src/models.rs @@ -0,0 +1,16 @@ +pub enum TruncationDirection { + Start, + End, +} + +pub trait LanguageModel { + fn name(&self) -> String; + fn count_tokens(&self, content: &str) -> anyhow::Result; + fn truncate( + &self, + content: &str, + length: usize, + direction: TruncationDirection, + ) -> anyhow::Result; + fn capacity(&self) -> anyhow::Result; +} diff --git a/crates/ai2/src/prompts/base.rs b/crates/ai2/src/prompts/base.rs new file mode 100644 index 0000000000..29091d0f5b --- /dev/null +++ b/crates/ai2/src/prompts/base.rs @@ -0,0 +1,330 @@ +use std::cmp::Reverse; +use std::ops::Range; +use std::sync::Arc; + +use language2::BufferSnapshot; +use util::ResultExt; + +use crate::models::LanguageModel; +use crate::prompts::repository_context::PromptCodeSnippet; + +pub(crate) enum PromptFileType { + Text, + Code, +} + +// TODO: Set this up to manage for defaults well +pub struct PromptArguments { + pub model: Arc, + pub user_prompt: Option, + pub language_name: Option, + pub project_name: Option, + pub snippets: Vec, + pub reserved_tokens: usize, + pub buffer: Option, + pub selected_range: Option>, +} + +impl PromptArguments { + pub(crate) fn get_file_type(&self) -> PromptFileType { + if self + .language_name + .as_ref() + .and_then(|name| Some(!["Markdown", "Plain Text"].contains(&name.as_str()))) + .unwrap_or(true) + { + PromptFileType::Code + } else { + PromptFileType::Text + } + } +} + +pub trait PromptTemplate { + fn generate( + &self, + args: &PromptArguments, + max_token_length: Option, + ) -> anyhow::Result<(String, usize)>; +} + +#[repr(i8)] +#[derive(PartialEq, Eq, Ord)] +pub enum PromptPriority { + Mandatory, // Ignores truncation + Ordered { order: usize }, // Truncates based on priority +} + +impl PartialOrd for PromptPriority { + fn partial_cmp(&self, other: &Self) -> Option { + match (self, other) { + (Self::Mandatory, Self::Mandatory) => Some(std::cmp::Ordering::Equal), + (Self::Mandatory, Self::Ordered { .. }) => Some(std::cmp::Ordering::Greater), + (Self::Ordered { .. }, Self::Mandatory) => Some(std::cmp::Ordering::Less), + (Self::Ordered { order: a }, Self::Ordered { order: b }) => b.partial_cmp(a), + } + } +} + +pub struct PromptChain { + args: PromptArguments, + templates: Vec<(PromptPriority, Box)>, +} + +impl PromptChain { + pub fn new( + args: PromptArguments, + templates: Vec<(PromptPriority, Box)>, + ) -> Self { + PromptChain { args, templates } + } + + pub fn generate(&self, truncate: bool) -> anyhow::Result<(String, usize)> { + // Argsort based on Prompt Priority + let seperator = "\n"; + let seperator_tokens = self.args.model.count_tokens(seperator)?; + let mut sorted_indices = (0..self.templates.len()).collect::>(); + sorted_indices.sort_by_key(|&i| Reverse(&self.templates[i].0)); + + // If Truncate + let mut tokens_outstanding = if truncate { + Some(self.args.model.capacity()? - self.args.reserved_tokens) + } else { + None + }; + + let mut prompts = vec!["".to_string(); sorted_indices.len()]; + for idx in sorted_indices { + let (_, template) = &self.templates[idx]; + + if let Some((template_prompt, prompt_token_count)) = + template.generate(&self.args, tokens_outstanding).log_err() + { + if template_prompt != "" { + prompts[idx] = template_prompt; + + if let Some(remaining_tokens) = tokens_outstanding { + let new_tokens = prompt_token_count + seperator_tokens; + tokens_outstanding = if remaining_tokens > new_tokens { + Some(remaining_tokens - new_tokens) + } else { + Some(0) + }; + } + } + } + } + + prompts.retain(|x| x != ""); + + let full_prompt = prompts.join(seperator); + let total_token_count = self.args.model.count_tokens(&full_prompt)?; + anyhow::Ok((prompts.join(seperator), total_token_count)) + } +} + +#[cfg(test)] +pub(crate) mod tests { + use crate::models::TruncationDirection; + use crate::test::FakeLanguageModel; + + use super::*; + + #[test] + pub fn test_prompt_chain() { + struct TestPromptTemplate {} + impl PromptTemplate for TestPromptTemplate { + fn generate( + &self, + args: &PromptArguments, + max_token_length: Option, + ) -> anyhow::Result<(String, usize)> { + let mut content = "This is a test prompt template".to_string(); + + let mut token_count = args.model.count_tokens(&content)?; + if let Some(max_token_length) = max_token_length { + if token_count > max_token_length { + content = args.model.truncate( + &content, + max_token_length, + TruncationDirection::End, + )?; + token_count = max_token_length; + } + } + + anyhow::Ok((content, token_count)) + } + } + + struct TestLowPriorityTemplate {} + impl PromptTemplate for TestLowPriorityTemplate { + fn generate( + &self, + args: &PromptArguments, + max_token_length: Option, + ) -> anyhow::Result<(String, usize)> { + let mut content = "This is a low priority test prompt template".to_string(); + + let mut token_count = args.model.count_tokens(&content)?; + if let Some(max_token_length) = max_token_length { + if token_count > max_token_length { + content = args.model.truncate( + &content, + max_token_length, + TruncationDirection::End, + )?; + token_count = max_token_length; + } + } + + anyhow::Ok((content, token_count)) + } + } + + let model: Arc = Arc::new(FakeLanguageModel { capacity: 100 }); + let args = PromptArguments { + model: model.clone(), + language_name: None, + project_name: None, + snippets: Vec::new(), + reserved_tokens: 0, + buffer: None, + selected_range: None, + user_prompt: None, + }; + + let templates: Vec<(PromptPriority, Box)> = vec![ + ( + PromptPriority::Ordered { order: 0 }, + Box::new(TestPromptTemplate {}), + ), + ( + PromptPriority::Ordered { order: 1 }, + Box::new(TestLowPriorityTemplate {}), + ), + ]; + let chain = PromptChain::new(args, templates); + + let (prompt, token_count) = chain.generate(false).unwrap(); + + assert_eq!( + prompt, + "This is a test prompt template\nThis is a low priority test prompt template" + .to_string() + ); + + assert_eq!(model.count_tokens(&prompt).unwrap(), token_count); + + // Testing with Truncation Off + // Should ignore capacity and return all prompts + let model: Arc = Arc::new(FakeLanguageModel { capacity: 20 }); + let args = PromptArguments { + model: model.clone(), + language_name: None, + project_name: None, + snippets: Vec::new(), + reserved_tokens: 0, + buffer: None, + selected_range: None, + user_prompt: None, + }; + + let templates: Vec<(PromptPriority, Box)> = vec![ + ( + PromptPriority::Ordered { order: 0 }, + Box::new(TestPromptTemplate {}), + ), + ( + PromptPriority::Ordered { order: 1 }, + Box::new(TestLowPriorityTemplate {}), + ), + ]; + let chain = PromptChain::new(args, templates); + + let (prompt, token_count) = chain.generate(false).unwrap(); + + assert_eq!( + prompt, + "This is a test prompt template\nThis is a low priority test prompt template" + .to_string() + ); + + assert_eq!(model.count_tokens(&prompt).unwrap(), token_count); + + // Testing with Truncation Off + // Should ignore capacity and return all prompts + let capacity = 20; + let model: Arc = Arc::new(FakeLanguageModel { capacity }); + let args = PromptArguments { + model: model.clone(), + language_name: None, + project_name: None, + snippets: Vec::new(), + reserved_tokens: 0, + buffer: None, + selected_range: None, + user_prompt: None, + }; + + let templates: Vec<(PromptPriority, Box)> = vec![ + ( + PromptPriority::Ordered { order: 0 }, + Box::new(TestPromptTemplate {}), + ), + ( + PromptPriority::Ordered { order: 1 }, + Box::new(TestLowPriorityTemplate {}), + ), + ( + PromptPriority::Ordered { order: 2 }, + Box::new(TestLowPriorityTemplate {}), + ), + ]; + let chain = PromptChain::new(args, templates); + + let (prompt, token_count) = chain.generate(true).unwrap(); + + assert_eq!(prompt, "This is a test promp".to_string()); + assert_eq!(token_count, capacity); + + // Change Ordering of Prompts Based on Priority + let capacity = 120; + let reserved_tokens = 10; + let model: Arc = Arc::new(FakeLanguageModel { capacity }); + let args = PromptArguments { + model: model.clone(), + language_name: None, + project_name: None, + snippets: Vec::new(), + reserved_tokens, + buffer: None, + selected_range: None, + user_prompt: None, + }; + let templates: Vec<(PromptPriority, Box)> = vec![ + ( + PromptPriority::Mandatory, + Box::new(TestLowPriorityTemplate {}), + ), + ( + PromptPriority::Ordered { order: 0 }, + Box::new(TestPromptTemplate {}), + ), + ( + PromptPriority::Ordered { order: 1 }, + Box::new(TestLowPriorityTemplate {}), + ), + ]; + let chain = PromptChain::new(args, templates); + + let (prompt, token_count) = chain.generate(true).unwrap(); + + assert_eq!( + prompt, + "This is a low priority test prompt template\nThis is a test prompt template\nThis is a low priority test prompt " + .to_string() + ); + assert_eq!(token_count, capacity - reserved_tokens); + } +} diff --git a/crates/ai2/src/prompts/file_context.rs b/crates/ai2/src/prompts/file_context.rs new file mode 100644 index 0000000000..4a741beb24 --- /dev/null +++ b/crates/ai2/src/prompts/file_context.rs @@ -0,0 +1,164 @@ +use anyhow::anyhow; +use language2::BufferSnapshot; +use language2::ToOffset; + +use crate::models::LanguageModel; +use crate::models::TruncationDirection; +use crate::prompts::base::PromptArguments; +use crate::prompts::base::PromptTemplate; +use std::fmt::Write; +use std::ops::Range; +use std::sync::Arc; + +fn retrieve_context( + buffer: &BufferSnapshot, + selected_range: &Option>, + model: Arc, + max_token_count: Option, +) -> anyhow::Result<(String, usize, bool)> { + let mut prompt = String::new(); + let mut truncated = false; + if let Some(selected_range) = selected_range { + let start = selected_range.start.to_offset(buffer); + let end = selected_range.end.to_offset(buffer); + + let start_window = buffer.text_for_range(0..start).collect::(); + + let mut selected_window = String::new(); + if start == end { + write!(selected_window, "<|START|>").unwrap(); + } else { + write!(selected_window, "<|START|").unwrap(); + } + + write!( + selected_window, + "{}", + buffer.text_for_range(start..end).collect::() + ) + .unwrap(); + + if start != end { + write!(selected_window, "|END|>").unwrap(); + } + + let end_window = buffer.text_for_range(end..buffer.len()).collect::(); + + if let Some(max_token_count) = max_token_count { + let selected_tokens = model.count_tokens(&selected_window)?; + if selected_tokens > max_token_count { + return Err(anyhow!( + "selected range is greater than model context window, truncation not possible" + )); + }; + + let mut remaining_tokens = max_token_count - selected_tokens; + let start_window_tokens = model.count_tokens(&start_window)?; + let end_window_tokens = model.count_tokens(&end_window)?; + let outside_tokens = start_window_tokens + end_window_tokens; + if outside_tokens > remaining_tokens { + let (start_goal_tokens, end_goal_tokens) = + if start_window_tokens < end_window_tokens { + let start_goal_tokens = (remaining_tokens / 2).min(start_window_tokens); + remaining_tokens -= start_goal_tokens; + let end_goal_tokens = remaining_tokens.min(end_window_tokens); + (start_goal_tokens, end_goal_tokens) + } else { + let end_goal_tokens = (remaining_tokens / 2).min(end_window_tokens); + remaining_tokens -= end_goal_tokens; + let start_goal_tokens = remaining_tokens.min(start_window_tokens); + (start_goal_tokens, end_goal_tokens) + }; + + let truncated_start_window = + model.truncate(&start_window, start_goal_tokens, TruncationDirection::Start)?; + let truncated_end_window = + model.truncate(&end_window, end_goal_tokens, TruncationDirection::End)?; + writeln!( + prompt, + "{truncated_start_window}{selected_window}{truncated_end_window}" + ) + .unwrap(); + truncated = true; + } else { + writeln!(prompt, "{start_window}{selected_window}{end_window}").unwrap(); + } + } else { + // If we dont have a selected range, include entire file. + writeln!(prompt, "{}", &buffer.text()).unwrap(); + + // Dumb truncation strategy + if let Some(max_token_count) = max_token_count { + if model.count_tokens(&prompt)? > max_token_count { + truncated = true; + prompt = model.truncate(&prompt, max_token_count, TruncationDirection::End)?; + } + } + } + } + + let token_count = model.count_tokens(&prompt)?; + anyhow::Ok((prompt, token_count, truncated)) +} + +pub struct FileContext {} + +impl PromptTemplate for FileContext { + fn generate( + &self, + args: &PromptArguments, + max_token_length: Option, + ) -> anyhow::Result<(String, usize)> { + if let Some(buffer) = &args.buffer { + let mut prompt = String::new(); + // Add Initial Preamble + // TODO: Do we want to add the path in here? + writeln!( + prompt, + "The file you are currently working on has the following content:" + ) + .unwrap(); + + let language_name = args + .language_name + .clone() + .unwrap_or("".to_string()) + .to_lowercase(); + + let (context, _, truncated) = retrieve_context( + buffer, + &args.selected_range, + args.model.clone(), + max_token_length, + )?; + writeln!(prompt, "```{language_name}\n{context}\n```").unwrap(); + + if truncated { + writeln!(prompt, "Note the content has been truncated and only represents a portion of the file.").unwrap(); + } + + if let Some(selected_range) = &args.selected_range { + let start = selected_range.start.to_offset(buffer); + let end = selected_range.end.to_offset(buffer); + + if start == end { + writeln!(prompt, "In particular, the user's cursor is currently on the '<|START|>' span in the above content, with no text selected.").unwrap(); + } else { + writeln!(prompt, "In particular, the user has selected a section of the text between the '<|START|' and '|END|>' spans.").unwrap(); + } + } + + // Really dumb truncation strategy + if let Some(max_tokens) = max_token_length { + prompt = args + .model + .truncate(&prompt, max_tokens, TruncationDirection::End)?; + } + + let token_count = args.model.count_tokens(&prompt)?; + anyhow::Ok((prompt, token_count)) + } else { + Err(anyhow!("no buffer provided to retrieve file context from")) + } + } +} diff --git a/crates/ai2/src/prompts/generate.rs b/crates/ai2/src/prompts/generate.rs new file mode 100644 index 0000000000..c7be620107 --- /dev/null +++ b/crates/ai2/src/prompts/generate.rs @@ -0,0 +1,99 @@ +use crate::prompts::base::{PromptArguments, PromptFileType, PromptTemplate}; +use anyhow::anyhow; +use std::fmt::Write; + +pub fn capitalize(s: &str) -> String { + let mut c = s.chars(); + match c.next() { + None => String::new(), + Some(f) => f.to_uppercase().collect::() + c.as_str(), + } +} + +pub struct GenerateInlineContent {} + +impl PromptTemplate for GenerateInlineContent { + fn generate( + &self, + args: &PromptArguments, + max_token_length: Option, + ) -> anyhow::Result<(String, usize)> { + let Some(user_prompt) = &args.user_prompt else { + return Err(anyhow!("user prompt not provided")); + }; + + let file_type = args.get_file_type(); + let content_type = match &file_type { + PromptFileType::Code => "code", + PromptFileType::Text => "text", + }; + + let mut prompt = String::new(); + + if let Some(selected_range) = &args.selected_range { + if selected_range.start == selected_range.end { + writeln!( + prompt, + "Assume the cursor is located where the `<|START|>` span is." + ) + .unwrap(); + writeln!( + prompt, + "{} can't be replaced, so assume your answer will be inserted at the cursor.", + capitalize(content_type) + ) + .unwrap(); + writeln!( + prompt, + "Generate {content_type} based on the users prompt: {user_prompt}", + ) + .unwrap(); + } else { + writeln!(prompt, "Modify the user's selected {content_type} based upon the users prompt: '{user_prompt}'").unwrap(); + writeln!(prompt, "You must reply with only the adjusted {content_type} (within the '<|START|' and '|END|>' spans) not the entire file.").unwrap(); + writeln!(prompt, "Double check that you only return code and not the '<|START|' and '|END|'> spans").unwrap(); + } + } else { + writeln!( + prompt, + "Generate {content_type} based on the users prompt: {user_prompt}" + ) + .unwrap(); + } + + if let Some(language_name) = &args.language_name { + writeln!( + prompt, + "Your answer MUST always and only be valid {}.", + language_name + ) + .unwrap(); + } + writeln!(prompt, "Never make remarks about the output.").unwrap(); + writeln!( + prompt, + "Do not return anything else, except the generated {content_type}." + ) + .unwrap(); + + match file_type { + PromptFileType::Code => { + // writeln!(prompt, "Always wrap your code in a Markdown block.").unwrap(); + } + _ => {} + } + + // Really dumb truncation strategy + if let Some(max_tokens) = max_token_length { + prompt = args.model.truncate( + &prompt, + max_tokens, + crate::models::TruncationDirection::End, + )?; + } + + let token_count = args.model.count_tokens(&prompt)?; + + anyhow::Ok((prompt, token_count)) + } +} diff --git a/crates/ai2/src/prompts/mod.rs b/crates/ai2/src/prompts/mod.rs new file mode 100644 index 0000000000..0025269a44 --- /dev/null +++ b/crates/ai2/src/prompts/mod.rs @@ -0,0 +1,5 @@ +pub mod base; +pub mod file_context; +pub mod generate; +pub mod preamble; +pub mod repository_context; diff --git a/crates/ai2/src/prompts/preamble.rs b/crates/ai2/src/prompts/preamble.rs new file mode 100644 index 0000000000..92e0edeb78 --- /dev/null +++ b/crates/ai2/src/prompts/preamble.rs @@ -0,0 +1,52 @@ +use crate::prompts::base::{PromptArguments, PromptFileType, PromptTemplate}; +use std::fmt::Write; + +pub struct EngineerPreamble {} + +impl PromptTemplate for EngineerPreamble { + fn generate( + &self, + args: &PromptArguments, + max_token_length: Option, + ) -> anyhow::Result<(String, usize)> { + let mut prompts = Vec::new(); + + match args.get_file_type() { + PromptFileType::Code => { + prompts.push(format!( + "You are an expert {}engineer.", + args.language_name.clone().unwrap_or("".to_string()) + " " + )); + } + PromptFileType::Text => { + prompts.push("You are an expert engineer.".to_string()); + } + } + + if let Some(project_name) = args.project_name.clone() { + prompts.push(format!( + "You are currently working inside the '{project_name}' project in code editor Zed." + )); + } + + if let Some(mut remaining_tokens) = max_token_length { + let mut prompt = String::new(); + let mut total_count = 0; + for prompt_piece in prompts { + let prompt_token_count = + args.model.count_tokens(&prompt_piece)? + args.model.count_tokens("\n")?; + if remaining_tokens > prompt_token_count { + writeln!(prompt, "{prompt_piece}").unwrap(); + remaining_tokens -= prompt_token_count; + total_count += prompt_token_count; + } + } + + anyhow::Ok((prompt, total_count)) + } else { + let prompt = prompts.join("\n"); + let token_count = args.model.count_tokens(&prompt)?; + anyhow::Ok((prompt, token_count)) + } + } +} diff --git a/crates/ai2/src/prompts/repository_context.rs b/crates/ai2/src/prompts/repository_context.rs new file mode 100644 index 0000000000..1bb75de7d2 --- /dev/null +++ b/crates/ai2/src/prompts/repository_context.rs @@ -0,0 +1,98 @@ +use crate::prompts::base::{PromptArguments, PromptTemplate}; +use std::fmt::Write; +use std::{ops::Range, path::PathBuf}; + +use gpui2::{AsyncAppContext, Model}; +use language2::{Anchor, Buffer}; + +#[derive(Clone)] +pub struct PromptCodeSnippet { + path: Option, + language_name: Option, + content: String, +} + +impl PromptCodeSnippet { + pub fn new( + buffer: Model, + range: Range, + cx: &mut AsyncAppContext, + ) -> anyhow::Result { + let (content, language_name, file_path) = buffer.update(cx, |buffer, _| { + let snapshot = buffer.snapshot(); + let content = snapshot.text_for_range(range.clone()).collect::(); + + let language_name = buffer + .language() + .and_then(|language| Some(language.name().to_string().to_lowercase())); + + let file_path = buffer + .file() + .and_then(|file| Some(file.path().to_path_buf())); + + (content, language_name, file_path) + })?; + + anyhow::Ok(PromptCodeSnippet { + path: file_path, + language_name, + content, + }) + } +} + +impl ToString for PromptCodeSnippet { + fn to_string(&self) -> String { + let path = self + .path + .as_ref() + .and_then(|path| Some(path.to_string_lossy().to_string())) + .unwrap_or("".to_string()); + let language_name = self.language_name.clone().unwrap_or("".to_string()); + let content = self.content.clone(); + + format!("The below code snippet may be relevant from file: {path}\n```{language_name}\n{content}\n```") + } +} + +pub struct RepositoryContext {} + +impl PromptTemplate for RepositoryContext { + fn generate( + &self, + args: &PromptArguments, + max_token_length: Option, + ) -> anyhow::Result<(String, usize)> { + const MAXIMUM_SNIPPET_TOKEN_COUNT: usize = 500; + let template = "You are working inside a large repository, here are a few code snippets that may be useful."; + let mut prompt = String::new(); + + let mut remaining_tokens = max_token_length.clone(); + let seperator_token_length = args.model.count_tokens("\n")?; + for snippet in &args.snippets { + let mut snippet_prompt = template.to_string(); + let content = snippet.to_string(); + writeln!(snippet_prompt, "{content}").unwrap(); + + let token_count = args.model.count_tokens(&snippet_prompt)?; + if token_count <= MAXIMUM_SNIPPET_TOKEN_COUNT { + if let Some(tokens_left) = remaining_tokens { + if tokens_left >= token_count { + writeln!(prompt, "{snippet_prompt}").unwrap(); + remaining_tokens = if tokens_left >= (token_count + seperator_token_length) + { + Some(tokens_left - token_count - seperator_token_length) + } else { + Some(0) + }; + } + } else { + writeln!(prompt, "{snippet_prompt}").unwrap(); + } + } + } + + let total_token_count = args.model.count_tokens(&prompt)?; + anyhow::Ok((prompt, total_token_count)) + } +} diff --git a/crates/ai2/src/providers/mod.rs b/crates/ai2/src/providers/mod.rs new file mode 100644 index 0000000000..acd0f9d910 --- /dev/null +++ b/crates/ai2/src/providers/mod.rs @@ -0,0 +1 @@ +pub mod open_ai; diff --git a/crates/ai2/src/providers/open_ai/completion.rs b/crates/ai2/src/providers/open_ai/completion.rs new file mode 100644 index 0000000000..eca5611027 --- /dev/null +++ b/crates/ai2/src/providers/open_ai/completion.rs @@ -0,0 +1,306 @@ +use anyhow::{anyhow, Result}; +use async_trait::async_trait; +use futures::{ + future::BoxFuture, io::BufReader, stream::BoxStream, AsyncBufReadExt, AsyncReadExt, FutureExt, + Stream, StreamExt, +}; +use gpui2::{AppContext, Executor}; +use isahc::{http::StatusCode, Request, RequestExt}; +use parking_lot::RwLock; +use serde::{Deserialize, Serialize}; +use std::{ + env, + fmt::{self, Display}, + io, + sync::Arc, +}; +use util::ResultExt; + +use crate::{ + auth::{CredentialProvider, ProviderCredential}, + completion::{CompletionProvider, CompletionRequest}, + models::LanguageModel, +}; + +use crate::providers::open_ai::{OpenAILanguageModel, OPENAI_API_URL}; + +#[derive(Clone, Copy, Serialize, Deserialize, Debug, Eq, PartialEq)] +#[serde(rename_all = "lowercase")] +pub enum Role { + User, + Assistant, + System, +} + +impl Role { + pub fn cycle(&mut self) { + *self = match self { + Role::User => Role::Assistant, + Role::Assistant => Role::System, + Role::System => Role::User, + } + } +} + +impl Display for Role { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Role::User => write!(f, "User"), + Role::Assistant => write!(f, "Assistant"), + Role::System => write!(f, "System"), + } + } +} + +#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)] +pub struct RequestMessage { + pub role: Role, + pub content: String, +} + +#[derive(Debug, Default, Serialize)] +pub struct OpenAIRequest { + pub model: String, + pub messages: Vec, + pub stream: bool, + pub stop: Vec, + pub temperature: f32, +} + +impl CompletionRequest for OpenAIRequest { + fn data(&self) -> serde_json::Result { + serde_json::to_string(self) + } +} + +#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)] +pub struct ResponseMessage { + pub role: Option, + pub content: Option, +} + +#[derive(Deserialize, Debug)] +pub struct OpenAIUsage { + pub prompt_tokens: u32, + pub completion_tokens: u32, + pub total_tokens: u32, +} + +#[derive(Deserialize, Debug)] +pub struct ChatChoiceDelta { + pub index: u32, + pub delta: ResponseMessage, + pub finish_reason: Option, +} + +#[derive(Deserialize, Debug)] +pub struct OpenAIResponseStreamEvent { + pub id: Option, + pub object: String, + pub created: u32, + pub model: String, + pub choices: Vec, + pub usage: Option, +} + +pub async fn stream_completion( + credential: ProviderCredential, + executor: Arc, + request: Box, +) -> Result>> { + let api_key = match credential { + ProviderCredential::Credentials { api_key } => api_key, + _ => { + return Err(anyhow!("no credentials provider for completion")); + } + }; + + let (tx, rx) = futures::channel::mpsc::unbounded::>(); + + let json_data = request.data()?; + let mut response = Request::post(format!("{OPENAI_API_URL}/chat/completions")) + .header("Content-Type", "application/json") + .header("Authorization", format!("Bearer {}", api_key)) + .body(json_data)? + .send_async() + .await?; + + let status = response.status(); + if status == StatusCode::OK { + executor + .spawn(async move { + let mut lines = BufReader::new(response.body_mut()).lines(); + + fn parse_line( + line: Result, + ) -> Result> { + if let Some(data) = line?.strip_prefix("data: ") { + let event = serde_json::from_str(&data)?; + Ok(Some(event)) + } else { + Ok(None) + } + } + + while let Some(line) = lines.next().await { + if let Some(event) = parse_line(line).transpose() { + let done = event.as_ref().map_or(false, |event| { + event + .choices + .last() + .map_or(false, |choice| choice.finish_reason.is_some()) + }); + if tx.unbounded_send(event).is_err() { + break; + } + + if done { + break; + } + } + } + + anyhow::Ok(()) + }) + .detach(); + + Ok(rx) + } else { + let mut body = String::new(); + response.body_mut().read_to_string(&mut body).await?; + + #[derive(Deserialize)] + struct OpenAIResponse { + error: OpenAIError, + } + + #[derive(Deserialize)] + struct OpenAIError { + message: String, + } + + match serde_json::from_str::(&body) { + Ok(response) if !response.error.message.is_empty() => Err(anyhow!( + "Failed to connect to OpenAI API: {}", + response.error.message, + )), + + _ => Err(anyhow!( + "Failed to connect to OpenAI API: {} {}", + response.status(), + body, + )), + } + } +} + +#[derive(Clone)] +pub struct OpenAICompletionProvider { + model: OpenAILanguageModel, + credential: Arc>, + executor: Arc, +} + +impl OpenAICompletionProvider { + pub fn new(model_name: &str, executor: Arc) -> Self { + let model = OpenAILanguageModel::load(model_name); + let credential = Arc::new(RwLock::new(ProviderCredential::NoCredentials)); + Self { + model, + credential, + executor, + } + } +} + +#[async_trait] +impl CredentialProvider for OpenAICompletionProvider { + fn has_credentials(&self) -> bool { + match *self.credential.read() { + ProviderCredential::Credentials { .. } => true, + _ => false, + } + } + async fn retrieve_credentials(&self, cx: &mut AppContext) -> ProviderCredential { + let existing_credential = self.credential.read().clone(); + + let retrieved_credential = cx + .run_on_main(move |cx| match existing_credential { + ProviderCredential::Credentials { .. } => { + return existing_credential.clone(); + } + _ => { + if let Some(api_key) = env::var("OPENAI_API_KEY").log_err() { + return 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 { + return ProviderCredential::NoCredentials; + } + } + }) + .await; + + *self.credential.write() = retrieved_credential.clone(); + retrieved_credential + } + + async fn save_credentials(&self, cx: &mut AppContext, credential: ProviderCredential) { + *self.credential.write() = credential.clone(); + let credential = credential.clone(); + cx.run_on_main(move |cx| match credential { + ProviderCredential::Credentials { api_key } => { + cx.write_credentials(OPENAI_API_URL, "Bearer", api_key.as_bytes()) + .log_err(); + } + _ => {} + }) + .await; + } + async fn delete_credentials(&self, cx: &mut AppContext) { + cx.run_on_main(move |cx| cx.delete_credentials(OPENAI_API_URL).log_err()) + .await; + *self.credential.write() = ProviderCredential::NoCredentials; + } +} + +impl CompletionProvider for OpenAICompletionProvider { + fn base_model(&self) -> Box { + let model: Box = Box::new(self.model.clone()); + model + } + fn complete( + &self, + prompt: Box, + ) -> BoxFuture<'static, Result>>> { + // Currently the CompletionRequest for OpenAI, includes a 'model' parameter + // This means that the model is determined by the CompletionRequest and not the CompletionProvider, + // which is currently model based, due to the langauge model. + // At some point in the future we should rectify this. + let credential = self.credential.read().clone(); + let request = stream_completion(credential, self.executor.clone(), prompt); + async move { + let response = request.await?; + let stream = response + .filter_map(|response| async move { + match response { + Ok(mut response) => Some(Ok(response.choices.pop()?.delta.content?)), + Err(error) => Some(Err(error)), + } + }) + .boxed(); + Ok(stream) + } + .boxed() + } + fn box_clone(&self) -> Box { + Box::new((*self).clone()) + } +} diff --git a/crates/ai2/src/providers/open_ai/embedding.rs b/crates/ai2/src/providers/open_ai/embedding.rs new file mode 100644 index 0000000000..fc49c15134 --- /dev/null +++ b/crates/ai2/src/providers/open_ai/embedding.rs @@ -0,0 +1,313 @@ +use anyhow::{anyhow, Result}; +use async_trait::async_trait; +use futures::AsyncReadExt; +use gpui2::Executor; +use gpui2::{serde_json, AppContext}; +use isahc::http::StatusCode; +use isahc::prelude::Configurable; +use isahc::{AsyncBody, Response}; +use lazy_static::lazy_static; +use parking_lot::{Mutex, RwLock}; +use parse_duration::parse; +use postage::watch; +use serde::{Deserialize, Serialize}; +use std::env; +use std::ops::Add; +use std::sync::Arc; +use std::time::{Duration, Instant}; +use tiktoken_rs::{cl100k_base, CoreBPE}; +use util::http::{HttpClient, Request}; +use util::ResultExt; + +use crate::auth::{CredentialProvider, ProviderCredential}; +use crate::embedding::{Embedding, EmbeddingProvider}; +use crate::models::LanguageModel; +use crate::providers::open_ai::OpenAILanguageModel; + +use crate::providers::open_ai::OPENAI_API_URL; + +lazy_static! { + static ref OPENAI_BPE_TOKENIZER: CoreBPE = cl100k_base().unwrap(); +} + +#[derive(Clone)] +pub struct OpenAIEmbeddingProvider { + model: OpenAILanguageModel, + credential: Arc>, + pub client: Arc, + pub executor: Arc, + rate_limit_count_rx: watch::Receiver>, + rate_limit_count_tx: Arc>>>, +} + +#[derive(Serialize)] +struct OpenAIEmbeddingRequest<'a> { + model: &'static str, + input: Vec<&'a str>, +} + +#[derive(Deserialize)] +struct OpenAIEmbeddingResponse { + data: Vec, + usage: OpenAIEmbeddingUsage, +} + +#[derive(Debug, Deserialize)] +struct OpenAIEmbedding { + embedding: Vec, + index: usize, + object: String, +} + +#[derive(Deserialize)] +struct OpenAIEmbeddingUsage { + prompt_tokens: usize, + total_tokens: usize, +} + +impl OpenAIEmbeddingProvider { + pub fn new(client: Arc, executor: Arc) -> Self { + let (rate_limit_count_tx, rate_limit_count_rx) = watch::channel_with(None); + let rate_limit_count_tx = Arc::new(Mutex::new(rate_limit_count_tx)); + + let model = OpenAILanguageModel::load("text-embedding-ada-002"); + let credential = Arc::new(RwLock::new(ProviderCredential::NoCredentials)); + + OpenAIEmbeddingProvider { + model, + credential, + client, + executor, + rate_limit_count_rx, + rate_limit_count_tx, + } + } + + fn get_api_key(&self) -> Result { + match self.credential.read().clone() { + ProviderCredential::Credentials { api_key } => Ok(api_key), + _ => Err(anyhow!("api credentials not provided")), + } + } + + fn resolve_rate_limit(&self) { + let reset_time = *self.rate_limit_count_tx.lock().borrow(); + + if let Some(reset_time) = reset_time { + if Instant::now() >= reset_time { + *self.rate_limit_count_tx.lock().borrow_mut() = None + } + } + + log::trace!( + "resolving reset time: {:?}", + *self.rate_limit_count_tx.lock().borrow() + ); + } + + fn update_reset_time(&self, reset_time: Instant) { + let original_time = *self.rate_limit_count_tx.lock().borrow(); + + let updated_time = if let Some(original_time) = original_time { + if reset_time < original_time { + Some(reset_time) + } else { + Some(original_time) + } + } else { + Some(reset_time) + }; + + log::trace!("updating rate limit time: {:?}", updated_time); + + *self.rate_limit_count_tx.lock().borrow_mut() = updated_time; + } + async fn send_request( + &self, + api_key: &str, + spans: Vec<&str>, + request_timeout: u64, + ) -> Result> { + let request = Request::post("https://api.openai.com/v1/embeddings") + .redirect_policy(isahc::config::RedirectPolicy::Follow) + .timeout(Duration::from_secs(request_timeout)) + .header("Content-Type", "application/json") + .header("Authorization", format!("Bearer {}", api_key)) + .body( + serde_json::to_string(&OpenAIEmbeddingRequest { + input: spans.clone(), + model: "text-embedding-ada-002", + }) + .unwrap() + .into(), + )?; + + Ok(self.client.send(request).await?) + } +} + +#[async_trait] +impl CredentialProvider for OpenAIEmbeddingProvider { + fn has_credentials(&self) -> bool { + match *self.credential.read() { + ProviderCredential::Credentials { .. } => true, + _ => false, + } + } + async fn retrieve_credentials(&self, cx: &mut AppContext) -> ProviderCredential { + let existing_credential = self.credential.read().clone(); + + let retrieved_credential = cx + .run_on_main(move |cx| match existing_credential { + ProviderCredential::Credentials { .. } => { + return existing_credential.clone(); + } + _ => { + if let Some(api_key) = env::var("OPENAI_API_KEY").log_err() { + return 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 { + return ProviderCredential::NoCredentials; + } + } + }) + .await; + + *self.credential.write() = retrieved_credential.clone(); + retrieved_credential + } + + async fn save_credentials(&self, cx: &mut AppContext, credential: ProviderCredential) { + *self.credential.write() = credential.clone(); + let credential = credential.clone(); + cx.run_on_main(move |cx| match credential { + ProviderCredential::Credentials { api_key } => { + cx.write_credentials(OPENAI_API_URL, "Bearer", api_key.as_bytes()) + .log_err(); + } + _ => {} + }) + .await; + } + async fn delete_credentials(&self, cx: &mut AppContext) { + cx.run_on_main(move |cx| cx.delete_credentials(OPENAI_API_URL).log_err()) + .await; + *self.credential.write() = ProviderCredential::NoCredentials; + } +} + +#[async_trait] +impl EmbeddingProvider for OpenAIEmbeddingProvider { + fn base_model(&self) -> Box { + let model: Box = Box::new(self.model.clone()); + model + } + + fn max_tokens_per_batch(&self) -> usize { + 50000 + } + + fn rate_limit_expiration(&self) -> Option { + *self.rate_limit_count_rx.borrow() + } + + async fn embed_batch(&self, spans: Vec) -> Result> { + const BACKOFF_SECONDS: [usize; 4] = [3, 5, 15, 45]; + const MAX_RETRIES: usize = 4; + + let api_key = self.get_api_key()?; + + let mut request_number = 0; + let mut rate_limiting = false; + let mut request_timeout: u64 = 15; + let mut response: Response; + while request_number < MAX_RETRIES { + response = self + .send_request( + &api_key, + spans.iter().map(|x| &**x).collect(), + request_timeout, + ) + .await?; + + request_number += 1; + + match response.status() { + StatusCode::REQUEST_TIMEOUT => { + request_timeout += 5; + } + StatusCode::OK => { + let mut body = String::new(); + response.body_mut().read_to_string(&mut body).await?; + let response: OpenAIEmbeddingResponse = serde_json::from_str(&body)?; + + log::trace!( + "openai embedding completed. tokens: {:?}", + response.usage.total_tokens + ); + + // If we complete a request successfully that was previously rate_limited + // resolve the rate limit + if rate_limiting { + self.resolve_rate_limit() + } + + return Ok(response + .data + .into_iter() + .map(|embedding| Embedding::from(embedding.embedding)) + .collect()); + } + StatusCode::TOO_MANY_REQUESTS => { + rate_limiting = true; + let mut body = String::new(); + response.body_mut().read_to_string(&mut body).await?; + + let delay_duration = { + let delay = Duration::from_secs(BACKOFF_SECONDS[request_number - 1] as u64); + if let Some(time_to_reset) = + response.headers().get("x-ratelimit-reset-tokens") + { + if let Ok(time_str) = time_to_reset.to_str() { + parse(time_str).unwrap_or(delay) + } else { + delay + } + } else { + delay + } + }; + + // If we've previously rate limited, increment the duration but not the count + let reset_time = Instant::now().add(delay_duration); + self.update_reset_time(reset_time); + + log::trace!( + "openai rate limiting: waiting {:?} until lifted", + &delay_duration + ); + + self.executor.timer(delay_duration).await; + } + _ => { + let mut body = String::new(); + response.body_mut().read_to_string(&mut body).await?; + return Err(anyhow!( + "open ai bad request: {:?} {:?}", + &response.status(), + body + )); + } + } + } + Err(anyhow!("openai max retries")) + } +} diff --git a/crates/ai2/src/providers/open_ai/mod.rs b/crates/ai2/src/providers/open_ai/mod.rs new file mode 100644 index 0000000000..7d2f86045d --- /dev/null +++ b/crates/ai2/src/providers/open_ai/mod.rs @@ -0,0 +1,9 @@ +pub mod completion; +pub mod embedding; +pub mod model; + +pub use completion::*; +pub use embedding::*; +pub use model::OpenAILanguageModel; + +pub const OPENAI_API_URL: &'static str = "https://api.openai.com/v1"; diff --git a/crates/ai2/src/providers/open_ai/model.rs b/crates/ai2/src/providers/open_ai/model.rs new file mode 100644 index 0000000000..6e306c80b9 --- /dev/null +++ b/crates/ai2/src/providers/open_ai/model.rs @@ -0,0 +1,57 @@ +use anyhow::anyhow; +use tiktoken_rs::CoreBPE; +use util::ResultExt; + +use crate::models::{LanguageModel, TruncationDirection}; + +#[derive(Clone)] +pub struct OpenAILanguageModel { + name: String, + bpe: Option, +} + +impl OpenAILanguageModel { + pub fn load(model_name: &str) -> Self { + let bpe = tiktoken_rs::get_bpe_from_model(model_name).log_err(); + OpenAILanguageModel { + name: model_name.to_string(), + bpe, + } + } +} + +impl LanguageModel for OpenAILanguageModel { + fn name(&self) -> String { + self.name.clone() + } + fn count_tokens(&self, content: &str) -> anyhow::Result { + if let Some(bpe) = &self.bpe { + anyhow::Ok(bpe.encode_with_special_tokens(content).len()) + } else { + Err(anyhow!("bpe for open ai model was not retrieved")) + } + } + fn truncate( + &self, + content: &str, + length: usize, + direction: TruncationDirection, + ) -> anyhow::Result { + if let Some(bpe) = &self.bpe { + let tokens = bpe.encode_with_special_tokens(content); + if tokens.len() > length { + match direction { + TruncationDirection::End => bpe.decode(tokens[..length].to_vec()), + TruncationDirection::Start => bpe.decode(tokens[length..].to_vec()), + } + } else { + bpe.decode(tokens) + } + } else { + Err(anyhow!("bpe for open ai model was not retrieved")) + } + } + fn capacity(&self) -> anyhow::Result { + anyhow::Ok(tiktoken_rs::model::get_context_size(&self.name)) + } +} diff --git a/crates/ai2/src/providers/open_ai/new.rs b/crates/ai2/src/providers/open_ai/new.rs new file mode 100644 index 0000000000..c7d67f2ba1 --- /dev/null +++ b/crates/ai2/src/providers/open_ai/new.rs @@ -0,0 +1,11 @@ +pub trait LanguageModel { + fn name(&self) -> String; + fn count_tokens(&self, content: &str) -> anyhow::Result; + fn truncate( + &self, + content: &str, + length: usize, + direction: TruncationDirection, + ) -> anyhow::Result; + fn capacity(&self) -> anyhow::Result; +} diff --git a/crates/ai2/src/test.rs b/crates/ai2/src/test.rs new file mode 100644 index 0000000000..ee88529aec --- /dev/null +++ b/crates/ai2/src/test.rs @@ -0,0 +1,193 @@ +use std::{ + sync::atomic::{self, AtomicUsize, Ordering}, + time::Instant, +}; + +use async_trait::async_trait; +use futures::{channel::mpsc, future::BoxFuture, stream::BoxStream, FutureExt, StreamExt}; +use gpui2::AppContext; +use parking_lot::Mutex; + +use crate::{ + auth::{CredentialProvider, ProviderCredential}, + completion::{CompletionProvider, CompletionRequest}, + embedding::{Embedding, EmbeddingProvider}, + models::{LanguageModel, TruncationDirection}, +}; + +#[derive(Clone)] +pub struct FakeLanguageModel { + pub capacity: usize, +} + +impl LanguageModel for FakeLanguageModel { + fn name(&self) -> String { + "dummy".to_string() + } + fn count_tokens(&self, content: &str) -> anyhow::Result { + anyhow::Ok(content.chars().collect::>().len()) + } + fn truncate( + &self, + content: &str, + length: usize, + direction: TruncationDirection, + ) -> anyhow::Result { + println!("TRYING TO TRUNCATE: {:?}", length.clone()); + + if length > self.count_tokens(content)? { + println!("NOT TRUNCATING"); + return anyhow::Ok(content.to_string()); + } + + anyhow::Ok(match direction { + TruncationDirection::End => content.chars().collect::>()[..length] + .into_iter() + .collect::(), + TruncationDirection::Start => content.chars().collect::>()[length..] + .into_iter() + .collect::(), + }) + } + fn capacity(&self) -> anyhow::Result { + anyhow::Ok(self.capacity) + } +} + +pub struct FakeEmbeddingProvider { + pub embedding_count: AtomicUsize, +} + +impl Clone for FakeEmbeddingProvider { + fn clone(&self) -> Self { + FakeEmbeddingProvider { + embedding_count: AtomicUsize::new(self.embedding_count.load(Ordering::SeqCst)), + } + } +} + +impl Default for FakeEmbeddingProvider { + fn default() -> Self { + FakeEmbeddingProvider { + embedding_count: AtomicUsize::default(), + } + } +} + +impl FakeEmbeddingProvider { + pub fn embedding_count(&self) -> usize { + self.embedding_count.load(atomic::Ordering::SeqCst) + } + + pub fn embed_sync(&self, span: &str) -> Embedding { + let mut result = vec![1.0; 26]; + for letter in span.chars() { + let letter = letter.to_ascii_lowercase(); + if letter as u32 >= 'a' as u32 { + let ix = (letter as u32) - ('a' as u32); + if ix < 26 { + result[ix as usize] += 1.0; + } + } + } + + let norm = result.iter().map(|x| x * x).sum::().sqrt(); + for x in &mut result { + *x /= norm; + } + + result.into() + } +} + +#[async_trait] +impl CredentialProvider for FakeEmbeddingProvider { + fn has_credentials(&self) -> bool { + true + } + async fn retrieve_credentials(&self, _cx: &mut AppContext) -> ProviderCredential { + ProviderCredential::NotNeeded + } + async fn save_credentials(&self, _cx: &mut AppContext, _credential: ProviderCredential) {} + async fn delete_credentials(&self, _cx: &mut AppContext) {} +} + +#[async_trait] +impl EmbeddingProvider for FakeEmbeddingProvider { + fn base_model(&self) -> Box { + Box::new(FakeLanguageModel { capacity: 1000 }) + } + fn max_tokens_per_batch(&self) -> usize { + 1000 + } + + fn rate_limit_expiration(&self) -> Option { + None + } + + async fn embed_batch(&self, spans: Vec) -> anyhow::Result> { + self.embedding_count + .fetch_add(spans.len(), atomic::Ordering::SeqCst); + + anyhow::Ok(spans.iter().map(|span| self.embed_sync(span)).collect()) + } +} + +pub struct FakeCompletionProvider { + last_completion_tx: Mutex>>, +} + +impl Clone for FakeCompletionProvider { + fn clone(&self) -> Self { + Self { + last_completion_tx: Mutex::new(None), + } + } +} + +impl FakeCompletionProvider { + pub fn new() -> Self { + Self { + last_completion_tx: Mutex::new(None), + } + } + + pub fn send_completion(&self, completion: impl Into) { + let mut tx = self.last_completion_tx.lock(); + tx.as_mut().unwrap().try_send(completion.into()).unwrap(); + } + + pub fn finish_completion(&self) { + self.last_completion_tx.lock().take().unwrap(); + } +} + +#[async_trait] +impl CredentialProvider for FakeCompletionProvider { + fn has_credentials(&self) -> bool { + true + } + async fn retrieve_credentials(&self, _cx: &mut AppContext) -> ProviderCredential { + ProviderCredential::NotNeeded + } + async fn save_credentials(&self, _cx: &mut AppContext, _credential: ProviderCredential) {} + async fn delete_credentials(&self, _cx: &mut AppContext) {} +} + +impl CompletionProvider for FakeCompletionProvider { + fn base_model(&self) -> Box { + let model: Box = Box::new(FakeLanguageModel { capacity: 8190 }); + model + } + fn complete( + &self, + _prompt: Box, + ) -> BoxFuture<'static, anyhow::Result>>> { + let (tx, rx) = mpsc::channel(1); + *self.last_completion_tx.lock() = Some(tx); + async move { Ok(rx.map(|rx| Ok(rx)).boxed()) }.boxed() + } + fn box_clone(&self) -> Box { + Box::new((*self).clone()) + } +} diff --git a/crates/assistant/Cargo.toml b/crates/assistant/Cargo.toml index 256f4d8416..fc885f6b36 100644 --- a/crates/assistant/Cargo.toml +++ b/crates/assistant/Cargo.toml @@ -45,6 +45,7 @@ tiktoken-rs = "0.5" [dev-dependencies] editor = { path = "../editor", features = ["test-support"] } project = { path = "../project", features = ["test-support"] } +ai = { path = "../ai", features = ["test-support"]} ctor.workspace = true env_logger.workspace = true diff --git a/crates/assistant/src/assistant.rs b/crates/assistant/src/assistant.rs index 6c9b14333e..91d61a19f9 100644 --- a/crates/assistant/src/assistant.rs +++ b/crates/assistant/src/assistant.rs @@ -4,7 +4,7 @@ mod codegen; mod prompts; mod streaming_diff; -use ai::completion::Role; +use ai::providers::open_ai::Role; use anyhow::Result; pub use assistant_panel::AssistantPanel; use assistant_settings::OpenAIModel; diff --git a/crates/assistant/src/assistant_panel.rs b/crates/assistant/src/assistant_panel.rs index 0dee8be510..03eb3c238f 100644 --- a/crates/assistant/src/assistant_panel.rs +++ b/crates/assistant/src/assistant_panel.rs @@ -5,12 +5,14 @@ use crate::{ MessageId, MessageMetadata, MessageStatus, Role, SavedConversation, SavedConversationMetadata, SavedMessage, }; + use ai::{ - completion::{ - stream_completion, OpenAICompletionProvider, OpenAIRequest, RequestMessage, OPENAI_API_URL, - }, - templates::repository_context::PromptCodeSnippet, + auth::ProviderCredential, + completion::{CompletionProvider, CompletionRequest}, + providers::open_ai::{OpenAICompletionProvider, OpenAIRequest, RequestMessage}, }; + +use ai::prompts::repository_context::PromptCodeSnippet; use anyhow::{anyhow, Result}; use chrono::{DateTime, Local}; use client::{telemetry::AssistantKind, ClickhouseEvent, TelemetrySettings}; @@ -43,8 +45,8 @@ use search::BufferSearchBar; use semantic_index::{SemanticIndex, SemanticIndexStatus}; use settings::SettingsStore; use std::{ - cell::{Cell, RefCell}, - cmp, env, + cell::Cell, + cmp, fmt::Write, iter, ops::Range, @@ -97,8 +99,8 @@ pub fn init(cx: &mut AppContext) { cx.capture_action(ConversationEditor::copy); cx.add_action(ConversationEditor::split); cx.capture_action(ConversationEditor::cycle_message_role); - cx.add_action(AssistantPanel::save_api_key); - cx.add_action(AssistantPanel::reset_api_key); + cx.add_action(AssistantPanel::save_credentials); + cx.add_action(AssistantPanel::reset_credentials); cx.add_action(AssistantPanel::toggle_zoom); cx.add_action(AssistantPanel::deploy); cx.add_action(AssistantPanel::select_next_match); @@ -140,9 +142,8 @@ pub struct AssistantPanel { zoomed: bool, has_focus: bool, toolbar: ViewHandle, - api_key: Rc>>, + completion_provider: Box, api_key_editor: Option>, - has_read_credentials: bool, languages: Arc, fs: Arc, subscriptions: Vec, @@ -202,6 +203,11 @@ impl AssistantPanel { }); let semantic_index = SemanticIndex::global(cx); + // Defaulting currently to GPT4, allow for this to be set via config. + let completion_provider = Box::new(OpenAICompletionProvider::new( + "gpt-4", + cx.background().clone(), + )); let mut this = Self { workspace: workspace_handle, @@ -213,9 +219,8 @@ impl AssistantPanel { zoomed: false, has_focus: false, toolbar, - api_key: Rc::new(RefCell::new(None)), + completion_provider, api_key_editor: None, - has_read_credentials: false, languages: workspace.app_state().languages.clone(), fs: workspace.app_state().fs.clone(), width: None, @@ -254,10 +259,7 @@ impl AssistantPanel { cx: &mut ViewContext, ) { let this = if let Some(this) = workspace.panel::(cx) { - if this - .update(cx, |assistant, cx| assistant.load_api_key(cx)) - .is_some() - { + if this.update(cx, |assistant, _| assistant.has_credentials()) { this } else { workspace.focus_panel::(cx); @@ -289,12 +291,6 @@ impl AssistantPanel { cx: &mut ViewContext, project: &ModelHandle, ) { - let api_key = if let Some(api_key) = self.api_key.borrow().clone() { - api_key - } else { - return; - }; - let selection = editor.read(cx).selections.newest_anchor().clone(); if selection.start.excerpt_id != selection.end.excerpt_id { return; @@ -325,10 +321,13 @@ impl AssistantPanel { let inline_assist_id = post_inc(&mut self.next_inline_assist_id); let provider = Arc::new(OpenAICompletionProvider::new( - api_key, + "gpt-4", cx.background().clone(), )); + // Retrieve Credentials Authenticates the Provider + // provider.retrieve_credentials(cx); + let codegen = cx.add_model(|cx| { Codegen::new(editor.read(cx).buffer().clone(), codegen_kind, provider, cx) }); @@ -745,13 +744,14 @@ impl AssistantPanel { content: prompt, }); - let request = OpenAIRequest { + let request = Box::new(OpenAIRequest { model: model.full_name().into(), messages, stream: true, stop: vec!["|END|>".to_string()], temperature, - }; + }); + codegen.update(&mut cx, |codegen, cx| codegen.start(request, cx)); anyhow::Ok(()) }) @@ -811,7 +811,7 @@ impl AssistantPanel { fn new_conversation(&mut self, cx: &mut ViewContext) -> ViewHandle { let editor = cx.add_view(|cx| { ConversationEditor::new( - self.api_key.clone(), + self.completion_provider.clone(), self.languages.clone(), self.fs.clone(), self.workspace.clone(), @@ -870,17 +870,19 @@ impl AssistantPanel { } } - fn save_api_key(&mut self, _: &menu::Confirm, cx: &mut ViewContext) { + fn save_credentials(&mut self, _: &menu::Confirm, cx: &mut ViewContext) { if let Some(api_key) = self .api_key_editor .as_ref() .map(|editor| editor.read(cx).text(cx)) { if !api_key.is_empty() { - cx.platform() - .write_credentials(OPENAI_API_URL, "Bearer", api_key.as_bytes()) - .log_err(); - *self.api_key.borrow_mut() = Some(api_key); + let credential = ProviderCredential::Credentials { + api_key: api_key.clone(), + }; + + self.completion_provider.save_credentials(cx, credential); + self.api_key_editor.take(); cx.focus_self(); cx.notify(); @@ -890,9 +892,8 @@ impl AssistantPanel { } } - fn reset_api_key(&mut self, _: &ResetKey, cx: &mut ViewContext) { - cx.platform().delete_credentials(OPENAI_API_URL).log_err(); - self.api_key.take(); + fn reset_credentials(&mut self, _: &ResetKey, cx: &mut ViewContext) { + self.completion_provider.delete_credentials(cx); self.api_key_editor = Some(build_api_key_editor(cx)); cx.focus_self(); cx.notify(); @@ -1151,13 +1152,12 @@ impl AssistantPanel { let fs = self.fs.clone(); let workspace = self.workspace.clone(); - let api_key = self.api_key.clone(); let languages = self.languages.clone(); cx.spawn(|this, mut cx| async move { let saved_conversation = fs.load(&path).await?; let saved_conversation = serde_json::from_str(&saved_conversation)?; let conversation = cx.add_model(|cx| { - Conversation::deserialize(saved_conversation, path.clone(), api_key, languages, cx) + Conversation::deserialize(saved_conversation, path.clone(), languages, cx) }); this.update(&mut cx, |this, cx| { // If, by the time we've loaded the conversation, the user has already opened @@ -1181,30 +1181,12 @@ impl AssistantPanel { .position(|editor| editor.read(cx).conversation.read(cx).path.as_deref() == Some(path)) } - fn load_api_key(&mut self, cx: &mut ViewContext) -> Option { - if self.api_key.borrow().is_none() && !self.has_read_credentials { - self.has_read_credentials = true; - let api_key = if let Ok(api_key) = env::var("OPENAI_API_KEY") { - Some(api_key) - } else if let Some((_, api_key)) = cx - .platform() - .read_credentials(OPENAI_API_URL) - .log_err() - .flatten() - { - String::from_utf8(api_key).log_err() - } else { - None - }; - if let Some(api_key) = api_key { - *self.api_key.borrow_mut() = Some(api_key); - } else if self.api_key_editor.is_none() { - self.api_key_editor = Some(build_api_key_editor(cx)); - cx.notify(); - } - } + fn has_credentials(&mut self) -> bool { + self.completion_provider.has_credentials() + } - self.api_key.borrow().clone() + fn load_credentials(&mut self, cx: &mut ViewContext) { + self.completion_provider.retrieve_credentials(cx); } } @@ -1389,7 +1371,7 @@ impl Panel for AssistantPanel { fn set_active(&mut self, active: bool, cx: &mut ViewContext) { if active { - self.load_api_key(cx); + self.load_credentials(cx); if self.editors.is_empty() { self.new_conversation(cx); @@ -1454,10 +1436,10 @@ struct Conversation { token_count: Option, max_token_count: usize, pending_token_count: Task>, - api_key: Rc>>, pending_save: Task>, path: Option, _subscriptions: Vec, + completion_provider: Box, } impl Entity for Conversation { @@ -1466,9 +1448,9 @@ impl Entity for Conversation { impl Conversation { fn new( - api_key: Rc>>, language_registry: Arc, cx: &mut ModelContext, + completion_provider: Box, ) -> Self { let markdown = language_registry.language_for_name("Markdown"); let buffer = cx.add_model(|cx| { @@ -1507,8 +1489,8 @@ impl Conversation { _subscriptions: vec![cx.subscribe(&buffer, Self::handle_buffer_event)], pending_save: Task::ready(Ok(())), path: None, - api_key, buffer, + completion_provider, }; let message = MessageAnchor { id: MessageId(post_inc(&mut this.next_message_id.0)), @@ -1554,7 +1536,6 @@ impl Conversation { fn deserialize( saved_conversation: SavedConversation, path: PathBuf, - api_key: Rc>>, language_registry: Arc, cx: &mut ModelContext, ) -> Self { @@ -1563,6 +1544,10 @@ impl Conversation { None => Some(Uuid::new_v4().to_string()), }; let model = saved_conversation.model; + let completion_provider: Box = Box::new( + OpenAICompletionProvider::new(model.full_name(), cx.background().clone()), + ); + completion_provider.retrieve_credentials(cx); let markdown = language_registry.language_for_name("Markdown"); let mut message_anchors = Vec::new(); let mut next_message_id = MessageId(0); @@ -1609,8 +1594,8 @@ impl Conversation { _subscriptions: vec![cx.subscribe(&buffer, Self::handle_buffer_event)], pending_save: Task::ready(Ok(())), path: Some(path), - api_key, buffer, + completion_provider, }; this.count_remaining_tokens(cx); this @@ -1731,11 +1716,11 @@ impl Conversation { } if should_assist { - let Some(api_key) = self.api_key.borrow().clone() else { + if !self.completion_provider.has_credentials() { return Default::default(); - }; + } - let request = OpenAIRequest { + let request: Box = Box::new(OpenAIRequest { model: self.model.full_name().to_string(), messages: self .messages(cx) @@ -1745,9 +1730,9 @@ impl Conversation { stream: true, stop: vec![], temperature: 1.0, - }; + }); - let stream = stream_completion(api_key, cx.background().clone(), request); + let stream = self.completion_provider.complete(request); let assistant_message = self .insert_message_after(last_message_id, Role::Assistant, MessageStatus::Pending, cx) .unwrap(); @@ -1765,33 +1750,28 @@ impl Conversation { let mut messages = stream.await?; while let Some(message) = messages.next().await { - let mut message = message?; - if let Some(choice) = message.choices.pop() { - this.upgrade(&cx) - .ok_or_else(|| anyhow!("conversation was dropped"))? - .update(&mut cx, |this, cx| { - let text: Arc = choice.delta.content?.into(); - let message_ix = - this.message_anchors.iter().position(|message| { - message.id == assistant_message_id - })?; - this.buffer.update(cx, |buffer, cx| { - let offset = this.message_anchors[message_ix + 1..] - .iter() - .find(|message| message.start.is_valid(buffer)) - .map_or(buffer.len(), |message| { - message - .start - .to_offset(buffer) - .saturating_sub(1) - }); - buffer.edit([(offset..offset, text)], None, cx); - }); - cx.emit(ConversationEvent::StreamedCompletion); + let text = message?; - Some(()) + this.upgrade(&cx) + .ok_or_else(|| anyhow!("conversation was dropped"))? + .update(&mut cx, |this, cx| { + let message_ix = this + .message_anchors + .iter() + .position(|message| message.id == assistant_message_id)?; + this.buffer.update(cx, |buffer, cx| { + let offset = this.message_anchors[message_ix + 1..] + .iter() + .find(|message| message.start.is_valid(buffer)) + .map_or(buffer.len(), |message| { + message.start.to_offset(buffer).saturating_sub(1) + }); + buffer.edit([(offset..offset, text)], None, cx); }); - } + cx.emit(ConversationEvent::StreamedCompletion); + + Some(()) + }); smol::future::yield_now().await; } @@ -2013,57 +1993,54 @@ impl Conversation { fn summarize(&mut self, cx: &mut ModelContext) { if self.message_anchors.len() >= 2 && self.summary.is_none() { - let api_key = self.api_key.borrow().clone(); - if let Some(api_key) = api_key { - let messages = self - .messages(cx) - .take(2) - .map(|message| message.to_open_ai_message(self.buffer.read(cx))) - .chain(Some(RequestMessage { - role: Role::User, - content: - "Summarize the conversation into a short title without punctuation" - .into(), - })); - let request = OpenAIRequest { - model: self.model.full_name().to_string(), - messages: messages.collect(), - stream: true, - stop: vec![], - temperature: 1.0, - }; - - let stream = stream_completion(api_key, cx.background().clone(), request); - self.pending_summary = cx.spawn(|this, mut cx| { - async move { - let mut messages = stream.await?; - - while let Some(message) = messages.next().await { - let mut message = message?; - if let Some(choice) = message.choices.pop() { - let text = choice.delta.content.unwrap_or_default(); - this.update(&mut cx, |this, cx| { - this.summary - .get_or_insert(Default::default()) - .text - .push_str(&text); - cx.emit(ConversationEvent::SummaryChanged); - }); - } - } - - this.update(&mut cx, |this, cx| { - if let Some(summary) = this.summary.as_mut() { - summary.done = true; - cx.emit(ConversationEvent::SummaryChanged); - } - }); - - anyhow::Ok(()) - } - .log_err() - }); + if !self.completion_provider.has_credentials() { + return; } + + let messages = self + .messages(cx) + .take(2) + .map(|message| message.to_open_ai_message(self.buffer.read(cx))) + .chain(Some(RequestMessage { + role: Role::User, + content: "Summarize the conversation into a short title without punctuation" + .into(), + })); + let request: Box = Box::new(OpenAIRequest { + model: self.model.full_name().to_string(), + messages: messages.collect(), + stream: true, + stop: vec![], + temperature: 1.0, + }); + + let stream = self.completion_provider.complete(request); + self.pending_summary = cx.spawn(|this, mut cx| { + async move { + let mut messages = stream.await?; + + while let Some(message) = messages.next().await { + let text = message?; + this.update(&mut cx, |this, cx| { + this.summary + .get_or_insert(Default::default()) + .text + .push_str(&text); + cx.emit(ConversationEvent::SummaryChanged); + }); + } + + this.update(&mut cx, |this, cx| { + if let Some(summary) = this.summary.as_mut() { + summary.done = true; + cx.emit(ConversationEvent::SummaryChanged); + } + }); + + anyhow::Ok(()) + } + .log_err() + }); } } @@ -2224,13 +2201,14 @@ struct ConversationEditor { impl ConversationEditor { fn new( - api_key: Rc>>, + completion_provider: Box, language_registry: Arc, fs: Arc, workspace: WeakViewHandle, cx: &mut ViewContext, ) -> Self { - let conversation = cx.add_model(|cx| Conversation::new(api_key, language_registry, cx)); + let conversation = + cx.add_model(|cx| Conversation::new(language_registry, cx, completion_provider)); Self::for_conversation(conversation, fs, workspace, cx) } @@ -3419,6 +3397,7 @@ fn merge_ranges(ranges: &mut Vec>, buffer: &MultiBufferSnapshot) { mod tests { use super::*; use crate::MessageId; + use ai::test::FakeCompletionProvider; use gpui::AppContext; #[gpui::test] @@ -3426,7 +3405,9 @@ mod tests { cx.set_global(SettingsStore::test(cx)); init(cx); let registry = Arc::new(LanguageRegistry::test()); - let conversation = cx.add_model(|cx| Conversation::new(Default::default(), registry, cx)); + + let completion_provider = Box::new(FakeCompletionProvider::new()); + let conversation = cx.add_model(|cx| Conversation::new(registry, cx, completion_provider)); let buffer = conversation.read(cx).buffer.clone(); let message_1 = conversation.read(cx).message_anchors[0].clone(); @@ -3554,7 +3535,9 @@ mod tests { cx.set_global(SettingsStore::test(cx)); init(cx); let registry = Arc::new(LanguageRegistry::test()); - let conversation = cx.add_model(|cx| Conversation::new(Default::default(), registry, cx)); + let completion_provider = Box::new(FakeCompletionProvider::new()); + + let conversation = cx.add_model(|cx| Conversation::new(registry, cx, completion_provider)); let buffer = conversation.read(cx).buffer.clone(); let message_1 = conversation.read(cx).message_anchors[0].clone(); @@ -3650,7 +3633,8 @@ mod tests { cx.set_global(SettingsStore::test(cx)); init(cx); let registry = Arc::new(LanguageRegistry::test()); - let conversation = cx.add_model(|cx| Conversation::new(Default::default(), registry, cx)); + let completion_provider = Box::new(FakeCompletionProvider::new()); + let conversation = cx.add_model(|cx| Conversation::new(registry, cx, completion_provider)); let buffer = conversation.read(cx).buffer.clone(); let message_1 = conversation.read(cx).message_anchors[0].clone(); @@ -3732,8 +3716,9 @@ mod tests { cx.set_global(SettingsStore::test(cx)); init(cx); let registry = Arc::new(LanguageRegistry::test()); + let completion_provider = Box::new(FakeCompletionProvider::new()); let conversation = - cx.add_model(|cx| Conversation::new(Default::default(), registry.clone(), cx)); + cx.add_model(|cx| Conversation::new(registry.clone(), cx, completion_provider)); let buffer = conversation.read(cx).buffer.clone(); let message_0 = conversation.read(cx).message_anchors[0].id; let message_1 = conversation.update(cx, |conversation, cx| { @@ -3770,7 +3755,6 @@ mod tests { Conversation::deserialize( conversation.read(cx).serialize(cx), Default::default(), - Default::default(), registry.clone(), cx, ) diff --git a/crates/assistant/src/codegen.rs b/crates/assistant/src/codegen.rs index 6b79daba42..0466259b24 100644 --- a/crates/assistant/src/codegen.rs +++ b/crates/assistant/src/codegen.rs @@ -1,5 +1,5 @@ use crate::streaming_diff::{Hunk, StreamingDiff}; -use ai::completion::{CompletionProvider, OpenAIRequest}; +use ai::completion::{CompletionProvider, CompletionRequest}; use anyhow::Result; use editor::{Anchor, MultiBuffer, MultiBufferSnapshot, ToOffset, ToPoint}; use futures::{channel::mpsc, SinkExt, Stream, StreamExt}; @@ -96,7 +96,7 @@ impl Codegen { self.error.as_ref() } - pub fn start(&mut self, prompt: OpenAIRequest, cx: &mut ModelContext) { + pub fn start(&mut self, prompt: Box, cx: &mut ModelContext) { let range = self.range(); let snapshot = self.snapshot.clone(); let selected_text = snapshot @@ -336,17 +336,25 @@ fn strip_markdown_codeblock( #[cfg(test)] mod tests { use super::*; - use futures::{ - future::BoxFuture, - stream::{self, BoxStream}, - }; + use ai::test::FakeCompletionProvider; + use futures::stream::{self}; use gpui::{executor::Deterministic, TestAppContext}; use indoc::indoc; use language::{language_settings, tree_sitter_rust, Buffer, Language, LanguageConfig, Point}; - use parking_lot::Mutex; use rand::prelude::*; + use serde::Serialize; use settings::SettingsStore; - use smol::future::FutureExt; + + #[derive(Serialize)] + pub struct DummyCompletionRequest { + pub name: String, + } + + impl CompletionRequest for DummyCompletionRequest { + fn data(&self) -> serde_json::Result { + serde_json::to_string(self) + } + } #[gpui::test(iterations = 10)] async fn test_transform_autoindent( @@ -372,7 +380,7 @@ mod tests { let snapshot = buffer.snapshot(cx); snapshot.anchor_before(Point::new(1, 0))..snapshot.anchor_after(Point::new(4, 5)) }); - let provider = Arc::new(TestCompletionProvider::new()); + let provider = Arc::new(FakeCompletionProvider::new()); let codegen = cx.add_model(|cx| { Codegen::new( buffer.clone(), @@ -381,7 +389,11 @@ mod tests { cx, ) }); - codegen.update(cx, |codegen, cx| codegen.start(Default::default(), cx)); + + let request = Box::new(DummyCompletionRequest { + name: "test".to_string(), + }); + codegen.update(cx, |codegen, cx| codegen.start(request, cx)); let mut new_text = concat!( " let mut x = 0;\n", @@ -434,7 +446,7 @@ mod tests { let snapshot = buffer.snapshot(cx); snapshot.anchor_before(Point::new(1, 6)) }); - let provider = Arc::new(TestCompletionProvider::new()); + let provider = Arc::new(FakeCompletionProvider::new()); let codegen = cx.add_model(|cx| { Codegen::new( buffer.clone(), @@ -443,7 +455,11 @@ mod tests { cx, ) }); - codegen.update(cx, |codegen, cx| codegen.start(Default::default(), cx)); + + let request = Box::new(DummyCompletionRequest { + name: "test".to_string(), + }); + codegen.update(cx, |codegen, cx| codegen.start(request, cx)); let mut new_text = concat!( "t mut x = 0;\n", @@ -496,7 +512,7 @@ mod tests { let snapshot = buffer.snapshot(cx); snapshot.anchor_before(Point::new(1, 2)) }); - let provider = Arc::new(TestCompletionProvider::new()); + let provider = Arc::new(FakeCompletionProvider::new()); let codegen = cx.add_model(|cx| { Codegen::new( buffer.clone(), @@ -505,7 +521,11 @@ mod tests { cx, ) }); - codegen.update(cx, |codegen, cx| codegen.start(Default::default(), cx)); + + let request = Box::new(DummyCompletionRequest { + name: "test".to_string(), + }); + codegen.update(cx, |codegen, cx| codegen.start(request, cx)); let mut new_text = concat!( "let mut x = 0;\n", @@ -593,38 +613,6 @@ mod tests { } } - struct TestCompletionProvider { - last_completion_tx: Mutex>>, - } - - impl TestCompletionProvider { - fn new() -> Self { - Self { - last_completion_tx: Mutex::new(None), - } - } - - fn send_completion(&self, completion: impl Into) { - let mut tx = self.last_completion_tx.lock(); - tx.as_mut().unwrap().try_send(completion.into()).unwrap(); - } - - fn finish_completion(&self) { - self.last_completion_tx.lock().take().unwrap(); - } - } - - impl CompletionProvider for TestCompletionProvider { - fn complete( - &self, - _prompt: OpenAIRequest, - ) -> BoxFuture<'static, Result>>> { - let (tx, rx) = mpsc::channel(1); - *self.last_completion_tx.lock() = Some(tx); - async move { Ok(rx.map(|rx| Ok(rx)).boxed()) }.boxed() - } - } - fn rust_lang() -> Language { Language::new( LanguageConfig { diff --git a/crates/assistant/src/prompts.rs b/crates/assistant/src/prompts.rs index dffcbc2923..25af023c40 100644 --- a/crates/assistant/src/prompts.rs +++ b/crates/assistant/src/prompts.rs @@ -1,9 +1,10 @@ -use ai::models::{LanguageModel, OpenAILanguageModel}; -use ai::templates::base::{PromptArguments, PromptChain, PromptPriority, PromptTemplate}; -use ai::templates::file_context::FileContext; -use ai::templates::generate::GenerateInlineContent; -use ai::templates::preamble::EngineerPreamble; -use ai::templates::repository_context::{PromptCodeSnippet, RepositoryContext}; +use ai::models::LanguageModel; +use ai::prompts::base::{PromptArguments, PromptChain, PromptPriority, PromptTemplate}; +use ai::prompts::file_context::FileContext; +use ai::prompts::generate::GenerateInlineContent; +use ai::prompts::preamble::EngineerPreamble; +use ai::prompts::repository_context::{PromptCodeSnippet, RepositoryContext}; +use ai::providers::open_ai::OpenAILanguageModel; use language::{BufferSnapshot, OffsetRangeExt, ToOffset}; use std::cmp::{self, Reverse}; use std::ops::Range; diff --git a/crates/call2/Cargo.toml b/crates/call2/Cargo.toml index efc7ab326e..f0e47832ed 100644 --- a/crates/call2/Cargo.toml +++ b/crates/call2/Cargo.toml @@ -25,7 +25,7 @@ collections = { path = "../collections" } gpui2 = { path = "../gpui2" } log.workspace = true live_kit_client = { path = "../live_kit_client" } -fs = { path = "../fs" } +fs2 = { path = "../fs2" } language2 = { path = "../language2" } media = { path = "../media" } project2 = { path = "../project2" } @@ -43,7 +43,7 @@ serde_derive.workspace = true [dev-dependencies] client2 = { path = "../client2", features = ["test-support"] } -fs = { path = "../fs", features = ["test-support"] } +fs2 = { path = "../fs2", features = ["test-support"] } language2 = { path = "../language2", features = ["test-support"] } collections = { path = "../collections", features = ["test-support"] } gpui2 = { path = "../gpui2", features = ["test-support"] } diff --git a/crates/call2/src/call2.rs b/crates/call2/src/call2.rs index 1a514164ba..d8678b7ed4 100644 --- a/crates/call2/src/call2.rs +++ b/crates/call2/src/call2.rs @@ -12,8 +12,8 @@ use client2::{ use collections::HashSet; use futures::{future::Shared, FutureExt}; use gpui2::{ - AppContext, AsyncAppContext, Context, EventEmitter, Handle, ModelContext, Subscription, Task, - WeakHandle, + AppContext, AsyncAppContext, Context, EventEmitter, Model, ModelContext, Subscription, Task, + WeakModel, }; use postage::watch; use project2::Project; @@ -23,10 +23,10 @@ use std::sync::Arc; pub use participant::ParticipantLocation; pub use room::Room; -pub fn init(client: Arc, user_store: Handle, cx: &mut AppContext) { +pub fn init(client: Arc, user_store: Model, cx: &mut AppContext) { CallSettings::register(cx); - let active_call = cx.entity(|cx| ActiveCall::new(client, user_store, cx)); + let active_call = cx.build_model(|cx| ActiveCall::new(client, user_store, cx)); cx.set_global(active_call); } @@ -40,16 +40,16 @@ pub struct IncomingCall { /// Singleton global maintaining the user's participation in a room across workspaces. pub struct ActiveCall { - room: Option<(Handle, Vec)>, - pending_room_creation: Option, Arc>>>>, - location: Option>, + room: Option<(Model, Vec)>, + pending_room_creation: Option, Arc>>>>, + location: Option>, pending_invites: HashSet, incoming_call: ( watch::Sender>, watch::Receiver>, ), client: Arc, - user_store: Handle, + user_store: Model, _subscriptions: Vec, } @@ -58,11 +58,7 @@ impl EventEmitter for ActiveCall { } impl ActiveCall { - fn new( - client: Arc, - user_store: Handle, - cx: &mut ModelContext, - ) -> Self { + fn new(client: Arc, user_store: Model, cx: &mut ModelContext) -> Self { Self { room: None, pending_room_creation: None, @@ -84,7 +80,7 @@ impl ActiveCall { } async fn handle_incoming_call( - this: Handle, + this: Model, envelope: TypedEnvelope, _: Arc, mut cx: AsyncAppContext, @@ -112,7 +108,7 @@ impl ActiveCall { } async fn handle_call_canceled( - this: Handle, + this: Model, envelope: TypedEnvelope, _: Arc, mut cx: AsyncAppContext, @@ -129,14 +125,14 @@ impl ActiveCall { Ok(()) } - pub fn global(cx: &AppContext) -> Handle { - cx.global::>().clone() + pub fn global(cx: &AppContext) -> Model { + cx.global::>().clone() } pub fn invite( &mut self, called_user_id: u64, - initial_project: Option>, + initial_project: Option>, cx: &mut ModelContext, ) -> Task> { if !self.pending_invites.insert(called_user_id) { @@ -291,7 +287,7 @@ impl ActiveCall { &mut self, channel_id: u64, cx: &mut ModelContext, - ) -> Task>> { + ) -> Task>> { if let Some(room) = self.room().cloned() { if room.read(cx).channel_id() == Some(channel_id) { return Task::ready(Ok(room)); @@ -327,7 +323,7 @@ impl ActiveCall { pub fn share_project( &mut self, - project: Handle, + project: Model, cx: &mut ModelContext, ) -> Task> { if let Some((room, _)) = self.room.as_ref() { @@ -340,7 +336,7 @@ impl ActiveCall { pub fn unshare_project( &mut self, - project: Handle, + project: Model, cx: &mut ModelContext, ) -> Result<()> { if let Some((room, _)) = self.room.as_ref() { @@ -351,13 +347,13 @@ impl ActiveCall { } } - pub fn location(&self) -> Option<&WeakHandle> { + pub fn location(&self) -> Option<&WeakModel> { self.location.as_ref() } pub fn set_location( &mut self, - project: Option<&Handle>, + project: Option<&Model>, cx: &mut ModelContext, ) -> Task> { if project.is_some() || !*ZED_ALWAYS_ACTIVE { @@ -371,7 +367,7 @@ impl ActiveCall { fn set_room( &mut self, - room: Option>, + room: Option>, cx: &mut ModelContext, ) -> Task> { if room.as_ref() != self.room.as_ref().map(|room| &room.0) { @@ -407,7 +403,7 @@ impl ActiveCall { } } - pub fn room(&self) -> Option<&Handle> { + pub fn room(&self) -> Option<&Model> { self.room.as_ref().map(|(room, _)| room) } diff --git a/crates/call2/src/participant.rs b/crates/call2/src/participant.rs index c5c873a78a..7f3e91dbba 100644 --- a/crates/call2/src/participant.rs +++ b/crates/call2/src/participant.rs @@ -1,7 +1,7 @@ use anyhow::{anyhow, Result}; use client2::ParticipantIndex; use client2::{proto, User}; -use gpui2::WeakHandle; +use gpui2::WeakModel; pub use live_kit_client::Frame; use project2::Project; use std::{fmt, sync::Arc}; @@ -33,7 +33,7 @@ impl ParticipantLocation { #[derive(Clone, Default)] pub struct LocalParticipant { pub projects: Vec, - pub active_project: Option>, + pub active_project: Option>, } #[derive(Clone, Debug)] diff --git a/crates/call2/src/room.rs b/crates/call2/src/room.rs index 639191123f..b7bac52a8b 100644 --- a/crates/call2/src/room.rs +++ b/crates/call2/src/room.rs @@ -13,10 +13,10 @@ use client2::{ Client, ParticipantIndex, TypedEnvelope, User, UserStore, }; use collections::{BTreeMap, HashMap, HashSet}; -use fs::Fs; +use fs2::Fs; use futures::{FutureExt, StreamExt}; use gpui2::{ - AppContext, AsyncAppContext, Context, EventEmitter, Handle, ModelContext, Task, WeakHandle, + AppContext, AsyncAppContext, Context, EventEmitter, Model, ModelContext, Task, WeakModel, }; use language2::LanguageRegistry; use live_kit_client::{LocalTrackPublication, RemoteAudioTrackUpdate, RemoteVideoTrackUpdate}; @@ -61,8 +61,8 @@ pub struct Room { channel_id: Option, // live_kit: Option, status: RoomStatus, - shared_projects: HashSet>, - joined_projects: HashSet>, + shared_projects: HashSet>, + joined_projects: HashSet>, local_participant: LocalParticipant, remote_participants: BTreeMap, pending_participants: Vec>, @@ -70,7 +70,7 @@ pub struct Room { pending_call_count: usize, leave_when_empty: bool, client: Arc, - user_store: Handle, + user_store: Model, follows_by_leader_id_project_id: HashMap<(PeerId, u64), Vec>, client_subscriptions: Vec, _subscriptions: Vec, @@ -111,7 +111,7 @@ impl Room { channel_id: Option, live_kit_connection_info: Option, client: Arc, - user_store: Handle, + user_store: Model, cx: &mut ModelContext, ) -> Self { todo!() @@ -237,15 +237,15 @@ impl Room { pub(crate) fn create( called_user_id: u64, - initial_project: Option>, + initial_project: Option>, client: Arc, - user_store: Handle, + user_store: Model, cx: &mut AppContext, - ) -> Task>> { + ) -> Task>> { cx.spawn(move |mut cx| async move { let response = client.request(proto::CreateRoom {}).await?; let room_proto = response.room.ok_or_else(|| anyhow!("invalid room"))?; - let room = cx.entity(|cx| { + let room = cx.build_model(|cx| { Self::new( room_proto.id, None, @@ -283,9 +283,9 @@ impl Room { pub(crate) fn join_channel( channel_id: u64, client: Arc, - user_store: Handle, + user_store: Model, cx: &mut AppContext, - ) -> Task>> { + ) -> Task>> { cx.spawn(move |cx| async move { Self::from_join_response( client.request(proto::JoinChannel { channel_id }).await?, @@ -299,9 +299,9 @@ impl Room { pub(crate) fn join( call: &IncomingCall, client: Arc, - user_store: Handle, + user_store: Model, cx: &mut AppContext, - ) -> Task>> { + ) -> Task>> { let id = call.room_id; cx.spawn(move |cx| async move { Self::from_join_response( @@ -343,11 +343,11 @@ impl Room { fn from_join_response( response: proto::JoinRoomResponse, client: Arc, - user_store: Handle, + user_store: Model, mut cx: AsyncAppContext, - ) -> Result> { + ) -> Result> { let room_proto = response.room.ok_or_else(|| anyhow!("invalid room"))?; - let room = cx.entity(|cx| { + let room = cx.build_model(|cx| { Self::new( room_proto.id, response.channel_id, @@ -424,7 +424,7 @@ impl Room { } async fn maintain_connection( - this: WeakHandle, + this: WeakModel, client: Arc, mut cx: AsyncAppContext, ) -> Result<()> { @@ -661,7 +661,7 @@ impl Room { } async fn handle_room_updated( - this: Handle, + this: Model, envelope: TypedEnvelope, _: Arc, mut cx: AsyncAppContext, @@ -1101,7 +1101,7 @@ impl Room { language_registry: Arc, fs: Arc, cx: &mut ModelContext, - ) -> Task>> { + ) -> Task>> { let client = self.client.clone(); let user_store = self.user_store.clone(); cx.emit(Event::RemoteProjectJoined { project_id: id }); @@ -1125,7 +1125,7 @@ impl Room { pub(crate) fn share_project( &mut self, - project: Handle, + project: Model, cx: &mut ModelContext, ) -> Task> { if let Some(project_id) = project.read(cx).remote_id() { @@ -1161,7 +1161,7 @@ impl Room { pub(crate) fn unshare_project( &mut self, - project: Handle, + project: Model, cx: &mut ModelContext, ) -> Result<()> { let project_id = match project.read(cx).remote_id() { @@ -1175,7 +1175,7 @@ impl Room { pub(crate) fn set_location( &mut self, - project: Option<&Handle>, + project: Option<&Model>, cx: &mut ModelContext, ) -> Task> { if self.status.is_offline() { diff --git a/crates/client2/src/client2.rs b/crates/client2/src/client2.rs index 8eaf248521..19e8685c28 100644 --- a/crates/client2/src/client2.rs +++ b/crates/client2/src/client2.rs @@ -14,8 +14,8 @@ use futures::{ future::BoxFuture, AsyncReadExt, FutureExt, SinkExt, StreamExt, TryFutureExt as _, TryStreamExt, }; use gpui2::{ - serde_json, AnyHandle, AnyWeakHandle, AppContext, AsyncAppContext, Handle, SemanticVersion, - Task, WeakHandle, + serde_json, AnyModel, AnyWeakModel, AppContext, AsyncAppContext, Model, SemanticVersion, Task, + WeakModel, }; use lazy_static::lazy_static; use parking_lot::RwLock; @@ -227,7 +227,7 @@ struct ClientState { _reconnect_task: Option>, reconnect_interval: Duration, entities_by_type_and_remote_id: HashMap<(TypeId, u64), WeakSubscriber>, - models_by_message_type: HashMap, + models_by_message_type: HashMap, entity_types_by_message_type: HashMap, #[allow(clippy::type_complexity)] message_handlers: HashMap< @@ -236,7 +236,7 @@ struct ClientState { dyn Send + Sync + Fn( - AnyHandle, + AnyModel, Box, &Arc, AsyncAppContext, @@ -246,7 +246,7 @@ struct ClientState { } enum WeakSubscriber { - Entity { handle: AnyWeakHandle }, + Entity { handle: AnyWeakModel }, Pending(Vec>), } @@ -314,7 +314,7 @@ impl PendingEntitySubscription where T: 'static + Send, { - pub fn set_model(mut self, model: &Handle, cx: &mut AsyncAppContext) -> Subscription { + pub fn set_model(mut self, model: &Model, cx: &mut AsyncAppContext) -> Subscription { self.consumed = true; let mut state = self.client.state.write(); let id = (TypeId::of::(), self.remote_id); @@ -552,13 +552,13 @@ impl Client { #[track_caller] pub fn add_message_handler( self: &Arc, - entity: WeakHandle, + entity: WeakModel, handler: H, ) -> Subscription where M: EnvelopedMessage, E: 'static + Send, - H: 'static + Send + Sync + Fn(Handle, TypedEnvelope, Arc, AsyncAppContext) -> F, + H: 'static + Send + Sync + Fn(Model, TypedEnvelope, Arc, AsyncAppContext) -> F, F: 'static + Future> + Send, { let message_type_id = TypeId::of::(); @@ -594,13 +594,13 @@ impl Client { pub fn add_request_handler( self: &Arc, - model: WeakHandle, + model: WeakModel, handler: H, ) -> Subscription where M: RequestMessage, E: 'static + Send, - H: 'static + Send + Sync + Fn(Handle, TypedEnvelope, Arc, AsyncAppContext) -> F, + H: 'static + Send + Sync + Fn(Model, TypedEnvelope, Arc, AsyncAppContext) -> F, F: 'static + Future> + Send, { self.add_message_handler(model, move |handle, envelope, this, cx| { @@ -616,7 +616,7 @@ impl Client { where M: EntityMessage, E: 'static + Send, - H: 'static + Send + Sync + Fn(Handle, TypedEnvelope, Arc, AsyncAppContext) -> F, + H: 'static + Send + Sync + Fn(Model, TypedEnvelope, Arc, AsyncAppContext) -> F, F: 'static + Future> + Send, { self.add_entity_message_handler::(move |subscriber, message, client, cx| { @@ -628,7 +628,7 @@ impl Client { where M: EntityMessage, E: 'static + Send, - H: 'static + Send + Sync + Fn(AnyHandle, TypedEnvelope, Arc, AsyncAppContext) -> F, + H: 'static + Send + Sync + Fn(AnyModel, TypedEnvelope, Arc, AsyncAppContext) -> F, F: 'static + Future> + Send, { let model_type_id = TypeId::of::(); @@ -667,7 +667,7 @@ impl Client { where M: EntityMessage + RequestMessage, E: 'static + Send, - H: 'static + Send + Sync + Fn(Handle, TypedEnvelope, Arc, AsyncAppContext) -> F, + H: 'static + Send + Sync + Fn(Model, TypedEnvelope, Arc, AsyncAppContext) -> F, F: 'static + Future> + Send, { self.add_model_message_handler(move |entity, envelope, client, cx| { @@ -1546,7 +1546,7 @@ mod tests { let (done_tx1, mut done_rx1) = smol::channel::unbounded(); let (done_tx2, mut done_rx2) = smol::channel::unbounded(); client.add_model_message_handler( - move |model: Handle, _: TypedEnvelope, _, mut cx| { + move |model: Model, _: TypedEnvelope, _, mut cx| { match model.update(&mut cx, |model, _| model.id).unwrap() { 1 => done_tx1.try_send(()).unwrap(), 2 => done_tx2.try_send(()).unwrap(), @@ -1555,15 +1555,15 @@ mod tests { async { Ok(()) } }, ); - let model1 = cx.entity(|_| Model { + let model1 = cx.build_model(|_| TestModel { id: 1, subscription: None, }); - let model2 = cx.entity(|_| Model { + let model2 = cx.build_model(|_| TestModel { id: 2, subscription: None, }); - let model3 = cx.entity(|_| Model { + let model3 = cx.build_model(|_| TestModel { id: 3, subscription: None, }); @@ -1596,7 +1596,7 @@ mod tests { let client = cx.update(|cx| Client::new(FakeHttpClient::with_404_response(), cx)); let server = FakeServer::for_client(user_id, &client, cx).await; - let model = cx.entity(|_| Model::default()); + let model = cx.build_model(|_| TestModel::default()); let (done_tx1, _done_rx1) = smol::channel::unbounded(); let (done_tx2, mut done_rx2) = smol::channel::unbounded(); let subscription1 = client.add_message_handler( @@ -1624,11 +1624,11 @@ mod tests { let client = cx.update(|cx| Client::new(FakeHttpClient::with_404_response(), cx)); let server = FakeServer::for_client(user_id, &client, cx).await; - let model = cx.entity(|_| Model::default()); + let model = cx.build_model(|_| TestModel::default()); let (done_tx, mut done_rx) = smol::channel::unbounded(); let subscription = client.add_message_handler( model.clone().downgrade(), - move |model: Handle, _: TypedEnvelope, _, mut cx| { + move |model: Model, _: TypedEnvelope, _, mut cx| { model .update(&mut cx, |model, _| model.subscription.take()) .unwrap(); @@ -1644,7 +1644,7 @@ mod tests { } #[derive(Default)] - struct Model { + struct TestModel { id: usize, subscription: Option, } diff --git a/crates/client2/src/telemetry.rs b/crates/client2/src/telemetry.rs index 1b64e94107..47d1c143e1 100644 --- a/crates/client2/src/telemetry.rs +++ b/crates/client2/src/telemetry.rs @@ -5,7 +5,9 @@ use parking_lot::Mutex; use serde::Serialize; use settings2::Settings; use std::{env, io::Write, mem, path::PathBuf, sync::Arc, time::Duration}; -use sysinfo::{Pid, PidExt, ProcessExt, System, SystemExt}; +use sysinfo::{ + CpuRefreshKind, Pid, PidExt, ProcessExt, ProcessRefreshKind, RefreshKind, System, SystemExt, +}; use tempfile::NamedTempFile; use util::http::HttpClient; use util::{channel::ReleaseChannel, TryFutureExt}; @@ -161,8 +163,16 @@ impl Telemetry { let this = self.clone(); cx.spawn(|cx| async move { - let mut system = System::new_all(); - system.refresh_all(); + // Avoiding calling `System::new_all()`, as there have been crashes related to it + let refresh_kind = RefreshKind::new() + .with_memory() // For memory usage + .with_processes(ProcessRefreshKind::everything()) // For process usage + .with_cpu(CpuRefreshKind::everything()); // For core count + + let mut system = System::new_with_specifics(refresh_kind); + + // Avoiding calling `refresh_all()`, just update what we need + system.refresh_specifics(refresh_kind); loop { // Waiting some amount of time before the first query is important to get a reasonable value @@ -170,8 +180,7 @@ impl Telemetry { const DURATION_BETWEEN_SYSTEM_EVENTS: Duration = Duration::from_secs(60); smol::Timer::after(DURATION_BETWEEN_SYSTEM_EVENTS).await; - system.refresh_memory(); - system.refresh_processes(); + system.refresh_specifics(refresh_kind); let current_process = Pid::from_u32(std::process::id()); let Some(process) = system.processes().get(¤t_process) else { diff --git a/crates/client2/src/test.rs b/crates/client2/src/test.rs index 1b32d35092..f30547dcfc 100644 --- a/crates/client2/src/test.rs +++ b/crates/client2/src/test.rs @@ -1,7 +1,7 @@ use crate::{Client, Connection, Credentials, EstablishConnectionError, UserStore}; use anyhow::{anyhow, Result}; use futures::{stream::BoxStream, StreamExt}; -use gpui2::{Context, Executor, Handle, TestAppContext}; +use gpui2::{Context, Executor, Model, TestAppContext}; use parking_lot::Mutex; use rpc2::{ proto::{self, GetPrivateUserInfo, GetPrivateUserInfoResponse}, @@ -194,9 +194,9 @@ impl FakeServer { &self, client: Arc, cx: &mut TestAppContext, - ) -> Handle { + ) -> Model { let http_client = FakeHttpClient::with_404_response(); - let user_store = cx.entity(|cx| UserStore::new(client, http_client, cx)); + let user_store = cx.build_model(|cx| UserStore::new(client, http_client, cx)); assert_eq!( self.receive::() .await diff --git a/crates/client2/src/user.rs b/crates/client2/src/user.rs index 41cf46ea8f..a8be4b6401 100644 --- a/crates/client2/src/user.rs +++ b/crates/client2/src/user.rs @@ -3,7 +3,7 @@ use anyhow::{anyhow, Context, Result}; use collections::{hash_map::Entry, HashMap, HashSet}; use feature_flags2::FeatureFlagAppExt; use futures::{channel::mpsc, future, AsyncReadExt, Future, StreamExt}; -use gpui2::{AsyncAppContext, EventEmitter, Handle, ImageData, ModelContext, Task}; +use gpui2::{AsyncAppContext, EventEmitter, ImageData, Model, ModelContext, Task}; use postage::{sink::Sink, watch}; use rpc2::proto::{RequestMessage, UsersResponse}; use std::sync::{Arc, Weak}; @@ -213,7 +213,7 @@ impl UserStore { } async fn handle_update_invite_info( - this: Handle, + this: Model, message: TypedEnvelope, _: Arc, mut cx: AsyncAppContext, @@ -229,7 +229,7 @@ impl UserStore { } async fn handle_show_contacts( - this: Handle, + this: Model, _: TypedEnvelope, _: Arc, mut cx: AsyncAppContext, @@ -243,7 +243,7 @@ impl UserStore { } async fn handle_update_contacts( - this: Handle, + this: Model, message: TypedEnvelope, _: Arc, mut cx: AsyncAppContext, @@ -690,7 +690,7 @@ impl User { impl Contact { async fn from_proto( contact: proto::Contact, - user_store: &Handle, + user_store: &Model, cx: &mut AsyncAppContext, ) -> Result { let user = user_store diff --git a/crates/copilot2/src/copilot2.rs b/crates/copilot2/src/copilot2.rs index 149b01aa82..c3107a2f47 100644 --- a/crates/copilot2/src/copilot2.rs +++ b/crates/copilot2/src/copilot2.rs @@ -7,8 +7,8 @@ use async_tar::Archive; use collections::{HashMap, HashSet}; use futures::{channel::oneshot, future::Shared, Future, FutureExt, TryFutureExt}; use gpui2::{ - AppContext, AsyncAppContext, Context, EntityId, EventEmitter, Handle, ModelContext, Task, - WeakHandle, + AppContext, AsyncAppContext, Context, EntityId, EventEmitter, Model, ModelContext, Task, + WeakModel, }; use language2::{ language_settings::{all_language_settings, language_settings}, @@ -49,7 +49,7 @@ pub fn init( node_runtime: Arc, cx: &mut AppContext, ) { - let copilot = cx.entity({ + let copilot = cx.build_model({ let node_runtime = node_runtime.clone(); move |cx| Copilot::start(new_server_id, http, node_runtime, cx) }); @@ -183,7 +183,7 @@ struct RegisteredBuffer { impl RegisteredBuffer { fn report_changes( &mut self, - buffer: &Handle, + buffer: &Model, cx: &mut ModelContext, ) -> oneshot::Receiver<(i32, BufferSnapshot)> { let (done_tx, done_rx) = oneshot::channel(); @@ -278,7 +278,7 @@ pub struct Copilot { http: Arc, node_runtime: Arc, server: CopilotServer, - buffers: HashSet>, + buffers: HashSet>, server_id: LanguageServerId, _subscription: gpui2::Subscription, } @@ -292,9 +292,9 @@ impl EventEmitter for Copilot { } impl Copilot { - pub fn global(cx: &AppContext) -> Option> { - if cx.has_global::>() { - Some(cx.global::>().clone()) + pub fn global(cx: &AppContext) -> Option> { + if cx.has_global::>() { + Some(cx.global::>().clone()) } else { None } @@ -383,7 +383,7 @@ impl Copilot { new_server_id: LanguageServerId, http: Arc, node_runtime: Arc, - this: WeakHandle, + this: WeakModel, mut cx: AsyncAppContext, ) -> impl Future { async move { @@ -590,7 +590,7 @@ impl Copilot { } } - pub fn register_buffer(&mut self, buffer: &Handle, cx: &mut ModelContext) { + pub fn register_buffer(&mut self, buffer: &Model, cx: &mut ModelContext) { let weak_buffer = buffer.downgrade(); self.buffers.insert(weak_buffer.clone()); @@ -646,7 +646,7 @@ impl Copilot { fn handle_buffer_event( &mut self, - buffer: Handle, + buffer: Model, event: &language2::Event, cx: &mut ModelContext, ) -> Result<()> { @@ -706,7 +706,7 @@ impl Copilot { Ok(()) } - fn unregister_buffer(&mut self, buffer: &WeakHandle) { + fn unregister_buffer(&mut self, buffer: &WeakModel) { if let Ok(server) = self.server.as_running() { if let Some(buffer) = server.registered_buffers.remove(&buffer.entity_id()) { server @@ -723,7 +723,7 @@ impl Copilot { pub fn completions( &mut self, - buffer: &Handle, + buffer: &Model, position: T, cx: &mut ModelContext, ) -> Task>> @@ -735,7 +735,7 @@ impl Copilot { pub fn completions_cycling( &mut self, - buffer: &Handle, + buffer: &Model, position: T, cx: &mut ModelContext, ) -> Task>> @@ -792,7 +792,7 @@ impl Copilot { fn request_completions( &mut self, - buffer: &Handle, + buffer: &Model, position: T, cx: &mut ModelContext, ) -> Task>> @@ -926,7 +926,7 @@ fn id_for_language(language: Option<&Arc>) -> String { } } -fn uri_for_buffer(buffer: &Handle, cx: &AppContext) -> lsp2::Url { +fn uri_for_buffer(buffer: &Model, cx: &AppContext) -> lsp2::Url { if let Some(file) = buffer.read(cx).file().and_then(|file| file.as_local()) { lsp2::Url::from_file_path(file.abs_path(cx)).unwrap() } else { diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index bfb87afff2..4e449bb7f7 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -967,7 +967,6 @@ impl CompletionsMenu { self.selected_item -= 1; } else { self.selected_item = self.matches.len() - 1; - self.list.scroll_to(ScrollTarget::Show(self.selected_item)); } self.list.scroll_to(ScrollTarget::Show(self.selected_item)); self.attempt_resolve_selected_completion_documentation(project, cx); @@ -1538,7 +1537,6 @@ impl CodeActionsMenu { self.selected_item -= 1; } else { self.selected_item = self.actions.len() - 1; - self.list.scroll_to(ScrollTarget::Show(self.selected_item)); } self.list.scroll_to(ScrollTarget::Show(self.selected_item)); cx.notify(); @@ -1547,11 +1545,10 @@ impl CodeActionsMenu { fn select_next(&mut self, cx: &mut ViewContext) { if self.selected_item + 1 < self.actions.len() { self.selected_item += 1; - self.list.scroll_to(ScrollTarget::Show(self.selected_item)); } else { self.selected_item = 0; - self.list.scroll_to(ScrollTarget::Show(self.selected_item)); } + self.list.scroll_to(ScrollTarget::Show(self.selected_item)); cx.notify(); } diff --git a/crates/gpui2/src/app.rs b/crates/gpui2/src/app.rs index a4d574abcf..0aca9410a8 100644 --- a/crates/gpui2/src/app.rs +++ b/crates/gpui2/src/app.rs @@ -16,7 +16,7 @@ use crate::{ current_platform, image_cache::ImageCache, Action, AnyBox, AnyView, AnyWindowHandle, AppMetadata, AssetSource, ClipboardItem, Context, DispatchPhase, DisplayId, Executor, FocusEvent, FocusHandle, FocusId, KeyBinding, Keymap, LayoutId, MainThread, MainThreadOnly, - Pixels, Platform, Point, SharedString, SubscriberSet, Subscription, SvgRenderer, Task, + Pixels, Platform, Point, Render, SharedString, SubscriberSet, Subscription, SvgRenderer, Task, TextStyle, TextStyleRefinement, TextSystem, View, ViewContext, Window, WindowContext, WindowHandle, WindowId, }; @@ -309,10 +309,17 @@ impl AppContext { update: impl FnOnce(&mut V, &mut ViewContext<'_, '_, V>) -> R, ) -> Result where - V: 'static, + V: 'static + Send, { self.update_window(handle.any_handle, |cx| { - let root_view = cx.window.root_view.as_ref().unwrap().downcast().unwrap(); + let root_view = cx + .window + .root_view + .as_ref() + .unwrap() + .clone() + .downcast() + .unwrap(); root_view.update(cx, update) }) } @@ -685,7 +692,7 @@ impl AppContext { pub fn observe_release( &mut self, - handle: &Handle, + handle: &Model, mut on_release: impl FnMut(&mut E, &mut AppContext) + Send + 'static, ) -> Subscription { self.release_listeners.insert( @@ -750,35 +757,35 @@ impl AppContext { } impl Context for AppContext { - type EntityContext<'a, T> = ModelContext<'a, T>; + type ModelContext<'a, T> = ModelContext<'a, T>; type Result = T; /// Build an entity that is owned by the application. The given function will be invoked with - /// a `ModelContext` and must return an object representing the entity. A `Handle` will be returned + /// a `ModelContext` and must return an object representing the entity. A `Model` will be returned /// which can be used to access the entity in a context. - fn entity( + fn build_model( &mut self, - build_entity: impl FnOnce(&mut Self::EntityContext<'_, T>) -> T, - ) -> Handle { + build_model: impl FnOnce(&mut Self::ModelContext<'_, T>) -> T, + ) -> Model { self.update(|cx| { let slot = cx.entities.reserve(); - let entity = build_entity(&mut ModelContext::mutable(cx, slot.downgrade())); + let entity = build_model(&mut ModelContext::mutable(cx, slot.downgrade())); cx.entities.insert(slot, entity) }) } - /// Update the entity referenced by the given handle. The function is passed a mutable reference to the + /// Update the entity referenced by the given model. The function is passed a mutable reference to the /// entity along with a `ModelContext` for the entity. fn update_entity( &mut self, - handle: &Handle, - update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, T>) -> R, + model: &Model, + update: impl FnOnce(&mut T, &mut Self::ModelContext<'_, T>) -> R, ) -> R { self.update(|cx| { - let mut entity = cx.entities.lease(handle); + let mut entity = cx.entities.lease(model); let result = update( &mut entity, - &mut ModelContext::mutable(cx, handle.downgrade()), + &mut ModelContext::mutable(cx, model.downgrade()), ); cx.entities.end_lease(entity); result @@ -861,10 +868,17 @@ impl MainThread { update: impl FnOnce(&mut V, &mut MainThread>) -> R, ) -> Result where - V: 'static, + V: 'static + Send, { self.update_window(handle.any_handle, |cx| { - let root_view = cx.window.root_view.as_ref().unwrap().downcast().unwrap(); + let root_view = cx + .window + .root_view + .as_ref() + .unwrap() + .clone() + .downcast() + .unwrap(); root_view.update(cx, update) }) } @@ -872,7 +886,7 @@ impl MainThread { /// Opens a new window with the given option and the root view returned by the given function. /// The function is invoked with a `WindowContext`, which can be used to interact with window-specific /// functionality. - pub fn open_window( + pub fn open_window( &mut self, options: crate::WindowOptions, build_root_view: impl FnOnce(&mut WindowContext) -> View + Send + 'static, @@ -955,10 +969,8 @@ impl DerefMut for GlobalLease { /// Contains state associated with an active drag operation, started by dragging an element /// within the window or by dragging into the app from the underlying platform. pub(crate) struct AnyDrag { - pub drag_handle_view: Option, + pub view: AnyView, pub cursor_offset: Point, - pub state: AnyBox, - pub state_type: TypeId, } #[cfg(test)] diff --git a/crates/gpui2/src/app/async_context.rs b/crates/gpui2/src/app/async_context.rs index 5998917e52..a10f0eb9e7 100644 --- a/crates/gpui2/src/app/async_context.rs +++ b/crates/gpui2/src/app/async_context.rs @@ -1,6 +1,6 @@ use crate::{ - AnyWindowHandle, AppContext, Component, Context, Executor, Handle, MainThread, ModelContext, - Result, Task, View, ViewContext, VisualContext, WindowContext, WindowHandle, + AnyWindowHandle, AppContext, Context, Executor, MainThread, Model, ModelContext, Result, Task, + View, ViewContext, VisualContext, WindowContext, WindowHandle, }; use anyhow::Context as _; use derive_more::{Deref, DerefMut}; @@ -14,25 +14,25 @@ pub struct AsyncAppContext { } impl Context for AsyncAppContext { - type EntityContext<'a, T> = ModelContext<'a, T>; + type ModelContext<'a, T> = ModelContext<'a, T>; type Result = Result; - fn entity( + fn build_model( &mut self, - build_entity: impl FnOnce(&mut Self::EntityContext<'_, T>) -> T, - ) -> Self::Result> + build_model: impl FnOnce(&mut Self::ModelContext<'_, T>) -> T, + ) -> Self::Result> where T: 'static + Send, { let app = self.app.upgrade().context("app was released")?; let mut lock = app.lock(); // Need this to compile - Ok(lock.entity(build_entity)) + Ok(lock.build_model(build_model)) } fn update_entity( &mut self, - handle: &Handle, - update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, T>) -> R, + handle: &Model, + update: impl FnOnce(&mut T, &mut Self::ModelContext<'_, T>) -> R, ) -> Self::Result { let app = self.app.upgrade().context("app was released")?; let mut lock = app.lock(); // Need this to compile @@ -84,7 +84,7 @@ impl AsyncAppContext { update: impl FnOnce(&mut V, &mut ViewContext<'_, '_, V>) -> R, ) -> Result where - V: 'static, + V: 'static + Send, { let app = self.app.upgrade().context("app was released")?; let mut app_context = app.lock(); @@ -234,24 +234,24 @@ impl AsyncWindowContext { } impl Context for AsyncWindowContext { - type EntityContext<'a, T> = ModelContext<'a, T>; + type ModelContext<'a, T> = ModelContext<'a, T>; type Result = Result; - fn entity( + fn build_model( &mut self, - build_entity: impl FnOnce(&mut Self::EntityContext<'_, T>) -> T, - ) -> Result> + build_model: impl FnOnce(&mut Self::ModelContext<'_, T>) -> T, + ) -> Result> where T: 'static + Send, { self.app - .update_window(self.window, |cx| cx.entity(build_entity)) + .update_window(self.window, |cx| cx.build_model(build_model)) } fn update_entity( &mut self, - handle: &Handle, - update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, T>) -> R, + handle: &Model, + update: impl FnOnce(&mut T, &mut Self::ModelContext<'_, T>) -> R, ) -> Result { self.app .update_window(self.window, |cx| cx.update_entity(handle, update)) @@ -261,17 +261,15 @@ impl Context for AsyncWindowContext { impl VisualContext for AsyncWindowContext { type ViewContext<'a, 'w, V> = ViewContext<'a, 'w, V>; - fn build_view( + fn build_view( &mut self, - build_entity: impl FnOnce(&mut Self::ViewContext<'_, '_, V>) -> V, - render: impl Fn(&mut V, &mut ViewContext<'_, '_, V>) -> E + Send + 'static, + build_view_state: impl FnOnce(&mut Self::ViewContext<'_, '_, V>) -> V, ) -> Self::Result> where - E: Component, V: 'static + Send, { self.app - .update_window(self.window, |cx| cx.build_view(build_entity, render)) + .update_window(self.window, |cx| cx.build_view(build_view_state)) } fn update_view( diff --git a/crates/gpui2/src/app/entity_map.rs b/crates/gpui2/src/app/entity_map.rs index a1a070a911..7e0c5626a5 100644 --- a/crates/gpui2/src/app/entity_map.rs +++ b/crates/gpui2/src/app/entity_map.rs @@ -1,4 +1,4 @@ -use crate::{AnyBox, AppContext, Context, EntityHandle}; +use crate::{AnyBox, AppContext, Context}; use anyhow::{anyhow, Result}; use derive_more::{Deref, DerefMut}; use parking_lot::{RwLock, RwLockUpgradableReadGuard}; @@ -53,29 +53,29 @@ impl EntityMap { /// Reserve a slot for an entity, which you can subsequently use with `insert`. pub fn reserve(&self) -> Slot { let id = self.ref_counts.write().counts.insert(1.into()); - Slot(Handle::new(id, Arc::downgrade(&self.ref_counts))) + Slot(Model::new(id, Arc::downgrade(&self.ref_counts))) } /// Insert an entity into a slot obtained by calling `reserve`. - pub fn insert(&mut self, slot: Slot, entity: T) -> Handle + pub fn insert(&mut self, slot: Slot, entity: T) -> Model where T: 'static + Send, { - let handle = slot.0; - self.entities.insert(handle.entity_id, Box::new(entity)); - handle + let model = slot.0; + self.entities.insert(model.entity_id, Box::new(entity)); + model } /// Move an entity to the stack. - pub fn lease<'a, T>(&mut self, handle: &'a Handle) -> Lease<'a, T> { - self.assert_valid_context(handle); + pub fn lease<'a, T>(&mut self, model: &'a Model) -> Lease<'a, T> { + self.assert_valid_context(model); let entity = Some( self.entities - .remove(handle.entity_id) + .remove(model.entity_id) .expect("Circular entity lease. Is the entity already being updated?"), ); Lease { - handle, + model, entity, entity_type: PhantomData, } @@ -84,18 +84,18 @@ impl EntityMap { /// Return an entity after moving it to the stack. pub fn end_lease(&mut self, mut lease: Lease) { self.entities - .insert(lease.handle.entity_id, lease.entity.take().unwrap()); + .insert(lease.model.entity_id, lease.entity.take().unwrap()); } - pub fn read(&self, handle: &Handle) -> &T { - self.assert_valid_context(handle); - self.entities[handle.entity_id].downcast_ref().unwrap() + pub fn read(&self, model: &Model) -> &T { + self.assert_valid_context(model); + self.entities[model.entity_id].downcast_ref().unwrap() } - fn assert_valid_context(&self, handle: &AnyHandle) { + fn assert_valid_context(&self, model: &AnyModel) { debug_assert!( - Weak::ptr_eq(&handle.entity_map, &Arc::downgrade(&self.ref_counts)), - "used a handle with the wrong context" + Weak::ptr_eq(&model.entity_map, &Arc::downgrade(&self.ref_counts)), + "used a model with the wrong context" ); } @@ -115,7 +115,7 @@ impl EntityMap { pub struct Lease<'a, T> { entity: Option, - pub handle: &'a Handle, + pub model: &'a Model, entity_type: PhantomData, } @@ -143,15 +143,15 @@ impl<'a, T> Drop for Lease<'a, T> { } #[derive(Deref, DerefMut)] -pub struct Slot(Handle); +pub struct Slot(Model); -pub struct AnyHandle { +pub struct AnyModel { pub(crate) entity_id: EntityId, - entity_type: TypeId, + pub(crate) entity_type: TypeId, entity_map: Weak>, } -impl AnyHandle { +impl AnyModel { fn new(id: EntityId, entity_type: TypeId, entity_map: Weak>) -> Self { Self { entity_id: id, @@ -164,18 +164,18 @@ impl AnyHandle { self.entity_id } - pub fn downgrade(&self) -> AnyWeakHandle { - AnyWeakHandle { + pub fn downgrade(&self) -> AnyWeakModel { + AnyWeakModel { entity_id: self.entity_id, entity_type: self.entity_type, entity_ref_counts: self.entity_map.clone(), } } - pub fn downcast(&self) -> Option> { + pub fn downcast(&self) -> Option> { if TypeId::of::() == self.entity_type { - Some(Handle { - any_handle: self.clone(), + Some(Model { + any_model: self.clone(), entity_type: PhantomData, }) } else { @@ -184,16 +184,16 @@ impl AnyHandle { } } -impl Clone for AnyHandle { +impl Clone for AnyModel { fn clone(&self) -> Self { if let Some(entity_map) = self.entity_map.upgrade() { let entity_map = entity_map.read(); let count = entity_map .counts .get(self.entity_id) - .expect("detected over-release of a handle"); + .expect("detected over-release of a model"); let prev_count = count.fetch_add(1, SeqCst); - assert_ne!(prev_count, 0, "Detected over-release of a handle."); + assert_ne!(prev_count, 0, "Detected over-release of a model."); } Self { @@ -204,16 +204,16 @@ impl Clone for AnyHandle { } } -impl Drop for AnyHandle { +impl Drop for AnyModel { fn drop(&mut self) { if let Some(entity_map) = self.entity_map.upgrade() { let entity_map = entity_map.upgradable_read(); let count = entity_map .counts .get(self.entity_id) - .expect("Detected over-release of a handle."); + .expect("Detected over-release of a model."); let prev_count = count.fetch_sub(1, SeqCst); - assert_ne!(prev_count, 0, "Detected over-release of a handle."); + assert_ne!(prev_count, 0, "Detected over-release of a model."); if prev_count == 1 { // We were the last reference to this entity, so we can remove it. let mut entity_map = RwLockUpgradableReadGuard::upgrade(entity_map); @@ -223,60 +223,65 @@ impl Drop for AnyHandle { } } -impl From> for AnyHandle { - fn from(handle: Handle) -> Self { - handle.any_handle +impl From> for AnyModel { + fn from(model: Model) -> Self { + model.any_model } } -impl Hash for AnyHandle { +impl Hash for AnyModel { fn hash(&self, state: &mut H) { self.entity_id.hash(state); } } -impl PartialEq for AnyHandle { +impl PartialEq for AnyModel { fn eq(&self, other: &Self) -> bool { self.entity_id == other.entity_id } } -impl Eq for AnyHandle {} +impl Eq for AnyModel {} #[derive(Deref, DerefMut)] -pub struct Handle { +pub struct Model { #[deref] #[deref_mut] - any_handle: AnyHandle, - entity_type: PhantomData, + pub(crate) any_model: AnyModel, + pub(crate) entity_type: PhantomData, } -unsafe impl Send for Handle {} -unsafe impl Sync for Handle {} +unsafe impl Send for Model {} +unsafe impl Sync for Model {} -impl Handle { +impl Model { fn new(id: EntityId, entity_map: Weak>) -> Self where T: 'static, { Self { - any_handle: AnyHandle::new(id, TypeId::of::(), entity_map), + any_model: AnyModel::new(id, TypeId::of::(), entity_map), entity_type: PhantomData, } } - pub fn downgrade(&self) -> WeakHandle { - WeakHandle { - any_handle: self.any_handle.downgrade(), + pub fn downgrade(&self) -> WeakModel { + WeakModel { + any_model: self.any_model.downgrade(), entity_type: self.entity_type, } } + /// Convert this into a dynamically typed model. + pub fn into_any(self) -> AnyModel { + self.any_model + } + pub fn read<'a>(&self, cx: &'a AppContext) -> &'a T { cx.entities.read(self) } - /// Update the entity referenced by this handle with the given function. + /// Update the entity referenced by this model with the given function. /// /// The update function receives a context appropriate for its environment. /// When updating in an `AppContext`, it receives a `ModelContext`. @@ -284,7 +289,7 @@ impl Handle { pub fn update( &self, cx: &mut C, - update: impl FnOnce(&mut T, &mut C::EntityContext<'_, T>) -> R, + update: impl FnOnce(&mut T, &mut C::ModelContext<'_, T>) -> R, ) -> C::Result where C: Context, @@ -293,73 +298,54 @@ impl Handle { } } -impl Clone for Handle { +impl Clone for Model { fn clone(&self) -> Self { Self { - any_handle: self.any_handle.clone(), + any_model: self.any_model.clone(), entity_type: self.entity_type, } } } -impl std::fmt::Debug for Handle { +impl std::fmt::Debug for Model { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, - "Handle {{ entity_id: {:?}, entity_type: {:?} }}", - self.any_handle.entity_id, + "Model {{ entity_id: {:?}, entity_type: {:?} }}", + self.any_model.entity_id, type_name::() ) } } -impl Hash for Handle { +impl Hash for Model { fn hash(&self, state: &mut H) { - self.any_handle.hash(state); + self.any_model.hash(state); } } -impl PartialEq for Handle { +impl PartialEq for Model { fn eq(&self, other: &Self) -> bool { - self.any_handle == other.any_handle + self.any_model == other.any_model } } -impl Eq for Handle {} +impl Eq for Model {} -impl PartialEq> for Handle { - fn eq(&self, other: &WeakHandle) -> bool { - self.entity_id == other.entity_id - } -} - -impl EntityHandle for Handle { - type Weak = WeakHandle; - - fn entity_id(&self) -> EntityId { - self.entity_id - } - - fn downgrade(&self) -> Self::Weak { - self.downgrade() - } - - fn upgrade_from(weak: &Self::Weak) -> Option - where - Self: Sized, - { - weak.upgrade() +impl PartialEq> for Model { + fn eq(&self, other: &WeakModel) -> bool { + self.entity_id() == other.entity_id() } } #[derive(Clone)] -pub struct AnyWeakHandle { +pub struct AnyWeakModel { pub(crate) entity_id: EntityId, entity_type: TypeId, entity_ref_counts: Weak>, } -impl AnyWeakHandle { +impl AnyWeakModel { pub fn entity_id(&self) -> EntityId { self.entity_id } @@ -373,14 +359,14 @@ impl AnyWeakHandle { ref_count > 0 } - pub fn upgrade(&self) -> Option { + pub fn upgrade(&self) -> Option { let entity_map = self.entity_ref_counts.upgrade()?; entity_map .read() .counts .get(self.entity_id)? .fetch_add(1, SeqCst); - Some(AnyHandle { + Some(AnyModel { entity_id: self.entity_id, entity_type: self.entity_type, entity_map: self.entity_ref_counts.clone(), @@ -388,55 +374,55 @@ impl AnyWeakHandle { } } -impl From> for AnyWeakHandle { - fn from(handle: WeakHandle) -> Self { - handle.any_handle +impl From> for AnyWeakModel { + fn from(model: WeakModel) -> Self { + model.any_model } } -impl Hash for AnyWeakHandle { +impl Hash for AnyWeakModel { fn hash(&self, state: &mut H) { self.entity_id.hash(state); } } -impl PartialEq for AnyWeakHandle { +impl PartialEq for AnyWeakModel { fn eq(&self, other: &Self) -> bool { self.entity_id == other.entity_id } } -impl Eq for AnyWeakHandle {} +impl Eq for AnyWeakModel {} #[derive(Deref, DerefMut)] -pub struct WeakHandle { +pub struct WeakModel { #[deref] #[deref_mut] - any_handle: AnyWeakHandle, + any_model: AnyWeakModel, entity_type: PhantomData, } -unsafe impl Send for WeakHandle {} -unsafe impl Sync for WeakHandle {} +unsafe impl Send for WeakModel {} +unsafe impl Sync for WeakModel {} -impl Clone for WeakHandle { +impl Clone for WeakModel { fn clone(&self) -> Self { Self { - any_handle: self.any_handle.clone(), + any_model: self.any_model.clone(), entity_type: self.entity_type, } } } -impl WeakHandle { - pub fn upgrade(&self) -> Option> { - Some(Handle { - any_handle: self.any_handle.upgrade()?, +impl WeakModel { + pub fn upgrade(&self) -> Option> { + Some(Model { + any_model: self.any_model.upgrade()?, entity_type: self.entity_type, }) } - /// Update the entity referenced by this handle with the given function if + /// Update the entity referenced by this model with the given function if /// the referenced entity still exists. Returns an error if the entity has /// been released. /// @@ -446,7 +432,7 @@ impl WeakHandle { pub fn update( &self, cx: &mut C, - update: impl FnOnce(&mut T, &mut C::EntityContext<'_, T>) -> R, + update: impl FnOnce(&mut T, &mut C::ModelContext<'_, T>) -> R, ) -> Result where C: Context, @@ -460,22 +446,22 @@ impl WeakHandle { } } -impl Hash for WeakHandle { +impl Hash for WeakModel { fn hash(&self, state: &mut H) { - self.any_handle.hash(state); + self.any_model.hash(state); } } -impl PartialEq for WeakHandle { +impl PartialEq for WeakModel { fn eq(&self, other: &Self) -> bool { - self.any_handle == other.any_handle + self.any_model == other.any_model } } -impl Eq for WeakHandle {} +impl Eq for WeakModel {} -impl PartialEq> for WeakHandle { - fn eq(&self, other: &Handle) -> bool { - self.entity_id == other.entity_id +impl PartialEq> for WeakModel { + fn eq(&self, other: &Model) -> bool { + self.entity_id() == other.entity_id() } } diff --git a/crates/gpui2/src/app/model_context.rs b/crates/gpui2/src/app/model_context.rs index 8354bda9a8..356db2a7de 100644 --- a/crates/gpui2/src/app/model_context.rs +++ b/crates/gpui2/src/app/model_context.rs @@ -1,6 +1,6 @@ use crate::{ - AppContext, AsyncAppContext, Context, Effect, EntityId, EventEmitter, Handle, MainThread, - Reference, Subscription, Task, WeakHandle, + AppContext, AsyncAppContext, Context, Effect, EntityId, EventEmitter, MainThread, Model, + Reference, Subscription, Task, WeakModel, }; use derive_more::{Deref, DerefMut}; use futures::FutureExt; @@ -15,11 +15,11 @@ pub struct ModelContext<'a, T> { #[deref] #[deref_mut] app: Reference<'a, AppContext>, - model_state: WeakHandle, + model_state: WeakModel, } impl<'a, T: 'static> ModelContext<'a, T> { - pub(crate) fn mutable(app: &'a mut AppContext, model_state: WeakHandle) -> Self { + pub(crate) fn mutable(app: &'a mut AppContext, model_state: WeakModel) -> Self { Self { app: Reference::Mutable(app), model_state, @@ -30,20 +30,20 @@ impl<'a, T: 'static> ModelContext<'a, T> { self.model_state.entity_id } - pub fn handle(&self) -> Handle { + pub fn handle(&self) -> Model { self.weak_handle() .upgrade() .expect("The entity must be alive if we have a model context") } - pub fn weak_handle(&self) -> WeakHandle { + pub fn weak_handle(&self) -> WeakModel { self.model_state.clone() } pub fn observe( &mut self, - handle: &Handle, - mut on_notify: impl FnMut(&mut T, Handle, &mut ModelContext<'_, T>) + Send + 'static, + handle: &Model, + mut on_notify: impl FnMut(&mut T, Model, &mut ModelContext<'_, T>) + Send + 'static, ) -> Subscription where T: 'static + Send, @@ -65,10 +65,8 @@ impl<'a, T: 'static> ModelContext<'a, T> { pub fn subscribe( &mut self, - handle: &Handle, - mut on_event: impl FnMut(&mut T, Handle, &E::Event, &mut ModelContext<'_, T>) - + Send - + 'static, + handle: &Model, + mut on_event: impl FnMut(&mut T, Model, &E::Event, &mut ModelContext<'_, T>) + Send + 'static, ) -> Subscription where T: 'static + Send, @@ -107,7 +105,7 @@ impl<'a, T: 'static> ModelContext<'a, T> { pub fn observe_release( &mut self, - handle: &Handle, + handle: &Model, mut on_release: impl FnMut(&mut T, &mut E, &mut ModelContext<'_, T>) + Send + 'static, ) -> Subscription where @@ -182,7 +180,7 @@ impl<'a, T: 'static> ModelContext<'a, T> { pub fn spawn( &self, - f: impl FnOnce(WeakHandle, AsyncAppContext) -> Fut + Send + 'static, + f: impl FnOnce(WeakModel, AsyncAppContext) -> Fut + Send + 'static, ) -> Task where T: 'static, @@ -195,7 +193,7 @@ impl<'a, T: 'static> ModelContext<'a, T> { pub fn spawn_on_main( &self, - f: impl FnOnce(WeakHandle, MainThread) -> Fut + Send + 'static, + f: impl FnOnce(WeakModel, MainThread) -> Fut + Send + 'static, ) -> Task where Fut: Future + 'static, @@ -220,23 +218,23 @@ where } impl<'a, T> Context for ModelContext<'a, T> { - type EntityContext<'b, U> = ModelContext<'b, U>; + type ModelContext<'b, U> = ModelContext<'b, U>; type Result = U; - fn entity( + fn build_model( &mut self, - build_entity: impl FnOnce(&mut Self::EntityContext<'_, U>) -> U, - ) -> Handle + build_model: impl FnOnce(&mut Self::ModelContext<'_, U>) -> U, + ) -> Model where U: 'static + Send, { - self.app.entity(build_entity) + self.app.build_model(build_model) } fn update_entity( &mut self, - handle: &Handle, - update: impl FnOnce(&mut U, &mut Self::EntityContext<'_, U>) -> R, + handle: &Model, + update: impl FnOnce(&mut U, &mut Self::ModelContext<'_, U>) -> R, ) -> R { self.app.update_entity(handle, update) } diff --git a/crates/gpui2/src/app/test_context.rs b/crates/gpui2/src/app/test_context.rs index 230d80f71f..183d8afe10 100644 --- a/crates/gpui2/src/app/test_context.rs +++ b/crates/gpui2/src/app/test_context.rs @@ -1,5 +1,5 @@ use crate::{ - AnyWindowHandle, AppContext, AsyncAppContext, Context, Executor, Handle, MainThread, + AnyWindowHandle, AppContext, AsyncAppContext, Context, Executor, MainThread, Model, ModelContext, Result, Task, TestDispatcher, TestPlatform, WindowContext, }; use parking_lot::Mutex; @@ -12,24 +12,24 @@ pub struct TestAppContext { } impl Context for TestAppContext { - type EntityContext<'a, T> = ModelContext<'a, T>; + type ModelContext<'a, T> = ModelContext<'a, T>; type Result = T; - fn entity( + fn build_model( &mut self, - build_entity: impl FnOnce(&mut Self::EntityContext<'_, T>) -> T, - ) -> Self::Result> + build_model: impl FnOnce(&mut Self::ModelContext<'_, T>) -> T, + ) -> Self::Result> where T: 'static + Send, { let mut lock = self.app.lock(); - lock.entity(build_entity) + lock.build_model(build_model) } fn update_entity( &mut self, - handle: &Handle, - update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, T>) -> R, + handle: &Model, + update: impl FnOnce(&mut T, &mut Self::ModelContext<'_, T>) -> R, ) -> Self::Result { let mut lock = self.app.lock(); lock.update_entity(handle, update) diff --git a/crates/gpui2/src/element.rs b/crates/gpui2/src/element.rs index 6dc5bc0a93..a715ed30ee 100644 --- a/crates/gpui2/src/element.rs +++ b/crates/gpui2/src/element.rs @@ -4,7 +4,7 @@ pub(crate) use smallvec::SmallVec; use std::{any::Any, mem}; pub trait Element { - type ElementState: 'static; + type ElementState: 'static + Send; fn id(&self) -> Option; diff --git a/crates/gpui2/src/gpui2.rs b/crates/gpui2/src/gpui2.rs index 824236d340..0357c9e6b8 100644 --- a/crates/gpui2/src/gpui2.rs +++ b/crates/gpui2/src/gpui2.rs @@ -70,33 +70,31 @@ use taffy::TaffyLayoutEngine; type AnyBox = Box; pub trait Context { - type EntityContext<'a, T>; + type ModelContext<'a, T>; type Result; - fn entity( + fn build_model( &mut self, - build_entity: impl FnOnce(&mut Self::EntityContext<'_, T>) -> T, - ) -> Self::Result> + build_model: impl FnOnce(&mut Self::ModelContext<'_, T>) -> T, + ) -> Self::Result> where T: 'static + Send; fn update_entity( &mut self, - handle: &Handle, - update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, T>) -> R, + handle: &Model, + update: impl FnOnce(&mut T, &mut Self::ModelContext<'_, T>) -> R, ) -> Self::Result; } pub trait VisualContext: Context { type ViewContext<'a, 'w, V>; - fn build_view( + fn build_view( &mut self, - build_entity: impl FnOnce(&mut Self::ViewContext<'_, '_, V>) -> V, - render: impl Fn(&mut V, &mut ViewContext<'_, '_, V>) -> E + Send + 'static, + build_view_state: impl FnOnce(&mut Self::ViewContext<'_, '_, V>) -> V, ) -> Self::Result> where - E: Component, V: 'static + Send; fn update_view( @@ -140,37 +138,37 @@ impl DerefMut for MainThread { } impl Context for MainThread { - type EntityContext<'a, T> = MainThread>; + type ModelContext<'a, T> = MainThread>; type Result = C::Result; - fn entity( + fn build_model( &mut self, - build_entity: impl FnOnce(&mut Self::EntityContext<'_, T>) -> T, - ) -> Self::Result> + build_model: impl FnOnce(&mut Self::ModelContext<'_, T>) -> T, + ) -> Self::Result> where T: 'static + Send, { - self.0.entity(|cx| { + self.0.build_model(|cx| { let cx = unsafe { mem::transmute::< - &mut C::EntityContext<'_, T>, - &mut MainThread>, + &mut C::ModelContext<'_, T>, + &mut MainThread>, >(cx) }; - build_entity(cx) + build_model(cx) }) } fn update_entity( &mut self, - handle: &Handle, - update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, T>) -> R, + handle: &Model, + update: impl FnOnce(&mut T, &mut Self::ModelContext<'_, T>) -> R, ) -> Self::Result { self.0.update_entity(handle, |entity, cx| { let cx = unsafe { mem::transmute::< - &mut C::EntityContext<'_, T>, - &mut MainThread>, + &mut C::ModelContext<'_, T>, + &mut MainThread>, >(cx) }; update(entity, cx) @@ -181,27 +179,22 @@ impl Context for MainThread { impl VisualContext for MainThread { type ViewContext<'a, 'w, V> = MainThread>; - fn build_view( + fn build_view( &mut self, - build_entity: impl FnOnce(&mut Self::ViewContext<'_, '_, V>) -> V, - render: impl Fn(&mut V, &mut ViewContext<'_, '_, V>) -> E + Send + 'static, + build_view_state: impl FnOnce(&mut Self::ViewContext<'_, '_, V>) -> V, ) -> Self::Result> where - E: Component, V: 'static + Send, { - self.0.build_view( - |cx| { - let cx = unsafe { - mem::transmute::< - &mut C::ViewContext<'_, '_, V>, - &mut MainThread>, - >(cx) - }; - build_entity(cx) - }, - render, - ) + self.0.build_view(|cx| { + let cx = unsafe { + mem::transmute::< + &mut C::ViewContext<'_, '_, V>, + &mut MainThread>, + >(cx) + }; + build_view_state(cx) + }) } fn update_view( diff --git a/crates/gpui2/src/interactive.rs b/crates/gpui2/src/interactive.rs index a617792bfb..317d7cea61 100644 --- a/crates/gpui2/src/interactive.rs +++ b/crates/gpui2/src/interactive.rs @@ -1,7 +1,7 @@ use crate::{ - point, px, Action, AnyBox, AnyDrag, AppContext, BorrowWindow, Bounds, Component, - DispatchContext, DispatchPhase, Element, ElementId, FocusHandle, KeyMatch, Keystroke, - Modifiers, Overflow, Pixels, Point, SharedString, Size, Style, StyleRefinement, View, + div, point, px, Action, AnyDrag, AnyView, AppContext, BorrowWindow, Bounds, Component, + DispatchContext, DispatchPhase, Div, Element, ElementId, FocusHandle, KeyMatch, Keystroke, + Modifiers, Overflow, Pixels, Point, Render, SharedString, Size, Style, StyleRefinement, View, ViewContext, }; use collections::HashMap; @@ -258,17 +258,17 @@ pub trait StatelessInteractive: Element { self } - fn on_drop( + fn on_drop( mut self, - listener: impl Fn(&mut V, S, &mut ViewContext) + Send + 'static, + listener: impl Fn(&mut V, View, &mut ViewContext) + Send + 'static, ) -> Self where Self: Sized, { self.stateless_interaction().drop_listeners.push(( - TypeId::of::(), - Box::new(move |view, drag_state, cx| { - listener(view, *drag_state.downcast().unwrap(), cx); + TypeId::of::(), + Box::new(move |view, dragged_view, cx| { + listener(view, dragged_view.downcast().unwrap(), cx); }), )); self @@ -314,36 +314,22 @@ pub trait StatefulInteractive: StatelessInteractive { self } - fn on_drag( + fn on_drag( mut self, - listener: impl Fn(&mut V, &mut ViewContext) -> Drag + Send + 'static, + listener: impl Fn(&mut V, &mut ViewContext) -> View + Send + 'static, ) -> Self where Self: Sized, - S: Any + Send, - R: Fn(&mut V, &mut ViewContext) -> E, - R: 'static + Send, - E: Component, + W: 'static + Send + Render, { debug_assert!( self.stateful_interaction().drag_listener.is_none(), "calling on_drag more than once on the same element is not supported" ); self.stateful_interaction().drag_listener = - Some(Box::new(move |view_state, cursor_offset, cx| { - let drag = listener(view_state, cx); - let drag_handle_view = Some( - View::for_handle(cx.handle().upgrade().unwrap(), move |view_state, cx| { - (drag.render_drag_handle)(view_state, cx) - }) - .into_any(), - ); - AnyDrag { - drag_handle_view, - cursor_offset, - state: Box::new(drag.state), - state_type: TypeId::of::(), - } + Some(Box::new(move |view_state, cursor_offset, cx| AnyDrag { + view: listener(view_state, cx).into_any(), + cursor_offset, })); self } @@ -412,7 +398,7 @@ pub trait ElementInteraction: 'static + Send { if let Some(drag) = cx.active_drag.take() { for (state_type, group_drag_style) in &self.as_stateless().group_drag_over_styles { if let Some(group_bounds) = GroupBounds::get(&group_drag_style.group, cx) { - if *state_type == drag.state_type + if *state_type == drag.view.entity_type() && group_bounds.contains_point(&mouse_position) { style.refine(&group_drag_style.style); @@ -421,7 +407,8 @@ pub trait ElementInteraction: 'static + Send { } for (state_type, drag_over_style) in &self.as_stateless().drag_over_styles { - if *state_type == drag.state_type && bounds.contains_point(&mouse_position) { + if *state_type == drag.view.entity_type() && bounds.contains_point(&mouse_position) + { style.refine(drag_over_style); } } @@ -509,7 +496,7 @@ pub trait ElementInteraction: 'static + Send { cx.on_mouse_event(move |view, event: &MouseUpEvent, phase, cx| { if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) { if let Some(drag_state_type) = - cx.active_drag.as_ref().map(|drag| drag.state_type) + cx.active_drag.as_ref().map(|drag| drag.view.entity_type()) { for (drop_state_type, listener) in &drop_listeners { if *drop_state_type == drag_state_type { @@ -517,7 +504,7 @@ pub trait ElementInteraction: 'static + Send { .active_drag .take() .expect("checked for type drag state type above"); - listener(view, drag.state, cx); + listener(view, drag.view.clone(), cx); cx.notify(); cx.stop_propagation(); } @@ -685,7 +672,7 @@ impl From for StatefulInteraction { } } -type DropListener = dyn Fn(&mut V, AnyBox, &mut ViewContext) + 'static + Send; +type DropListener = dyn Fn(&mut V, AnyView, &mut ViewContext) + 'static + Send; pub struct StatelessInteraction { pub dispatch_context: DispatchContext, @@ -866,7 +853,7 @@ pub struct Drag where R: Fn(&mut V, &mut ViewContext) -> E, V: 'static, - E: Component, + E: Component<()>, { pub state: S, pub render_drag_handle: R, @@ -877,7 +864,7 @@ impl Drag where R: Fn(&mut V, &mut ViewContext) -> E, V: 'static, - E: Component, + E: Component<()>, { pub fn new(state: S, render_drag_handle: R) -> Self { Drag { @@ -888,6 +875,10 @@ where } } +// impl Render for Drag { +// // fn render(&mut self, cx: ViewContext) -> +// } + #[derive(Hash, PartialEq, Eq, Copy, Clone, Debug)] pub enum MouseButton { Left, @@ -995,6 +986,14 @@ impl Deref for MouseExitEvent { #[derive(Debug, Clone, Default)] pub struct ExternalPaths(pub(crate) SmallVec<[PathBuf; 2]>); +impl Render for ExternalPaths { + type Element = Div; + + fn render(&mut self, _: &mut ViewContext) -> Self::Element { + div() // Intentionally left empty because the platform will render icons for the dragged files + } +} + #[derive(Debug, Clone)] pub enum FileDropEvent { Entered { diff --git a/crates/gpui2/src/view.rs b/crates/gpui2/src/view.rs index a61fd10441..2b8794d869 100644 --- a/crates/gpui2/src/view.rs +++ b/crates/gpui2/src/view.rs @@ -1,45 +1,35 @@ use crate::{ - AnyBox, AnyElement, AppContext, AvailableSpace, BorrowWindow, Bounds, Component, Element, - ElementId, EntityHandle, EntityId, Flatten, Handle, LayoutId, Pixels, Size, ViewContext, - VisualContext, WeakHandle, WindowContext, + AnyBox, AnyElement, AnyModel, AppContext, AvailableSpace, BorrowWindow, Bounds, Component, + Element, ElementId, EntityHandle, EntityId, Flatten, LayoutId, Model, Pixels, Size, + ViewContext, VisualContext, WeakModel, WindowContext, }; use anyhow::{Context, Result}; -use parking_lot::Mutex; use std::{ - any::Any, + any::{Any, TypeId}, marker::PhantomData, - sync::{Arc, Weak}, + sync::Arc, }; -pub struct View { - pub(crate) state: Handle, - render: Arc) -> AnyElement + Send + 'static>>, +pub trait Render: 'static + Sized { + type Element: Element + 'static + Send; + + fn render(&mut self, cx: &mut ViewContext) -> Self::Element; } -impl View { - pub fn for_handle( - state: Handle, - render: impl Fn(&mut V, &mut ViewContext<'_, '_, V>) -> E + Send + 'static, - ) -> View - where - E: Component, - { - View { - state, - render: Arc::new(Mutex::new( - move |state: &mut V, cx: &mut ViewContext<'_, '_, V>| render(state, cx).render(), - )), - } - } +pub struct View { + pub(crate) model: Model, +} +impl View { pub fn into_any(self) -> AnyView { AnyView(Arc::new(self)) } +} +impl View { pub fn downgrade(&self) -> WeakView { WeakView { - state: self.state.downgrade(), - render: Arc::downgrade(&self.render), + model: self.model.downgrade(), } } @@ -55,20 +45,19 @@ impl View { } pub fn read<'a>(&self, cx: &'a AppContext) -> &'a V { - cx.entities.read(&self.state) + self.model.read(cx) } } impl Clone for View { fn clone(&self) -> Self { Self { - state: self.state.clone(), - render: self.render.clone(), + model: self.model.clone(), } } } -impl Component for View { +impl Component for View { fn render(self) -> AnyElement { AnyElement::new(EraseViewState { view: self, @@ -77,11 +66,14 @@ impl Component for View Element<()> for View { +impl Element<()> for View +where + V: Render, +{ type ElementState = AnyElement; - fn id(&self) -> Option { - Some(ElementId::View(self.state.entity_id)) + fn id(&self) -> Option { + Some(ElementId::View(self.model.entity_id)) } fn initialize( @@ -91,7 +83,7 @@ impl Element<()> for View { cx: &mut ViewContext<()>, ) -> Self::ElementState { self.update(cx, |state, cx| { - let mut any_element = (self.render.lock())(state, cx); + let mut any_element = AnyElement::new(state.render(cx)); any_element.initialize(state, cx); any_element }) @@ -121,7 +113,7 @@ impl EntityHandle for View { type Weak = WeakView; fn entity_id(&self) -> EntityId { - self.state.entity_id + self.model.entity_id } fn downgrade(&self) -> Self::Weak { @@ -137,15 +129,13 @@ impl EntityHandle for View { } pub struct WeakView { - pub(crate) state: WeakHandle, - render: Weak) -> AnyElement + Send + 'static>>, + pub(crate) model: WeakModel, } impl WeakView { pub fn upgrade(&self) -> Option> { - let state = self.state.upgrade()?; - let render = self.render.upgrade()?; - Some(View { state, render }) + let model = self.model.upgrade()?; + Some(View { model }) } pub fn update( @@ -165,8 +155,7 @@ impl WeakView { impl Clone for WeakView { fn clone(&self) -> Self { Self { - state: self.state.clone(), - render: self.render.clone(), + model: self.model.clone(), } } } @@ -178,13 +167,13 @@ struct EraseViewState { unsafe impl Send for EraseViewState {} -impl Component for EraseViewState { +impl Component for EraseViewState { fn render(self) -> AnyElement { AnyElement::new(self) } } -impl Element for EraseViewState { +impl Element for EraseViewState { type ElementState = AnyBox; fn id(&self) -> Option { @@ -221,30 +210,43 @@ impl Element for EraseViewState TypeId; fn entity_id(&self) -> EntityId; + fn model(&self) -> AnyModel; fn initialize(&self, cx: &mut WindowContext) -> AnyBox; fn layout(&self, element: &mut AnyBox, cx: &mut WindowContext) -> LayoutId; fn paint(&self, bounds: Bounds, element: &mut AnyBox, cx: &mut WindowContext); fn as_any(&self) -> &dyn Any; } -impl ViewObject for View { +impl ViewObject for View +where + V: Render, +{ + fn entity_type(&self) -> TypeId { + TypeId::of::() + } + fn entity_id(&self) -> EntityId { - self.state.entity_id + self.model.entity_id + } + + fn model(&self) -> AnyModel { + self.model.clone().into_any() } fn initialize(&self, cx: &mut WindowContext) -> AnyBox { - cx.with_element_id(self.state.entity_id, |_global_id, cx| { + cx.with_element_id(self.model.entity_id, |_global_id, cx| { self.update(cx, |state, cx| { - let mut any_element = Box::new((self.render.lock())(state, cx)); + let mut any_element = Box::new(AnyElement::new(state.render(cx))); any_element.initialize(state, cx); - any_element as AnyBox + any_element }) }) } fn layout(&self, element: &mut AnyBox, cx: &mut WindowContext) -> LayoutId { - cx.with_element_id(self.state.entity_id, |_global_id, cx| { + cx.with_element_id(self.model.entity_id, |_global_id, cx| { self.update(cx, |state, cx| { let element = element.downcast_mut::>().unwrap(); element.layout(state, cx) @@ -253,7 +255,7 @@ impl ViewObject for View { } fn paint(&self, _: Bounds, element: &mut AnyBox, cx: &mut WindowContext) { - cx.with_element_id(self.state.entity_id, |_global_id, cx| { + cx.with_element_id(self.model.entity_id, |_global_id, cx| { self.update(cx, |state, cx| { let element = element.downcast_mut::>().unwrap(); element.paint(state, cx); @@ -270,8 +272,12 @@ impl ViewObject for View { pub struct AnyView(Arc); impl AnyView { - pub fn downcast(&self) -> Option> { - self.0.as_any().downcast_ref().cloned() + pub fn downcast(self) -> Option> { + self.0.model().downcast().map(|model| View { model }) + } + + pub(crate) fn entity_type(&self) -> TypeId { + self.0.entity_type() } pub(crate) fn draw(&self, available_space: Size, cx: &mut WindowContext) { @@ -343,6 +349,18 @@ impl Component for EraseAnyViewState { } } +impl Render for T +where + T: 'static + FnMut(&mut WindowContext) -> E, + E: 'static + Send + Element, +{ + type Element = E; + + fn render(&mut self, cx: &mut ViewContext) -> Self::Element { + (self)(cx) + } +} + impl Element for EraseAnyViewState { type ElementState = AnyBox; diff --git a/crates/gpui2/src/window.rs b/crates/gpui2/src/window.rs index 0f2dcc7049..2cf706eda4 100644 --- a/crates/gpui2/src/window.rs +++ b/crates/gpui2/src/window.rs @@ -1,14 +1,14 @@ use crate::{ px, size, Action, AnyBox, AnyDrag, AnyView, AppContext, AsyncWindowContext, AvailableSpace, Bounds, BoxShadow, Context, Corners, DevicePixels, DispatchContext, DisplayId, Edges, Effect, - EntityHandle, EntityId, EventEmitter, ExternalPaths, FileDropEvent, FocusEvent, FontId, - GlobalElementId, GlyphId, Handle, Hsla, ImageData, InputEvent, IsZero, KeyListener, KeyMatch, - KeyMatcher, Keystroke, LayoutId, MainThread, MainThreadOnly, ModelContext, Modifiers, - MonochromeSprite, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Path, Pixels, - PlatformAtlas, PlatformWindow, Point, PolychromeSprite, Quad, Reference, RenderGlyphParams, - RenderImageParams, RenderSvgParams, ScaledPixels, SceneBuilder, Shadow, SharedString, Size, - Style, Subscription, TaffyLayoutEngine, Task, Underline, UnderlineStyle, View, VisualContext, - WeakHandle, WeakView, WindowOptions, SUBPIXEL_VARIANTS, + EntityHandle, EntityId, EventEmitter, FileDropEvent, FocusEvent, FontId, GlobalElementId, + GlyphId, Hsla, ImageData, InputEvent, IsZero, KeyListener, KeyMatch, KeyMatcher, Keystroke, + LayoutId, MainThread, MainThreadOnly, Model, ModelContext, Modifiers, MonochromeSprite, + MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Path, Pixels, PlatformAtlas, + PlatformWindow, Point, PolychromeSprite, Quad, Reference, RenderGlyphParams, RenderImageParams, + RenderSvgParams, ScaledPixels, SceneBuilder, Shadow, SharedString, Size, Style, Subscription, + TaffyLayoutEngine, Task, Underline, UnderlineStyle, View, VisualContext, WeakModel, WeakView, + WindowOptions, SUBPIXEL_VARIANTS, }; use anyhow::Result; use collections::HashMap; @@ -918,15 +918,13 @@ impl<'a, 'w> WindowContext<'a, 'w> { root_view.draw(available_space, cx); }); - if let Some(mut active_drag) = self.app.active_drag.take() { + if let Some(active_drag) = self.app.active_drag.take() { self.stack(1, |cx| { let offset = cx.mouse_position() - active_drag.cursor_offset; cx.with_element_offset(Some(offset), |cx| { let available_space = size(AvailableSpace::MinContent, AvailableSpace::MinContent); - if let Some(drag_handle_view) = &mut active_drag.drag_handle_view { - drag_handle_view.draw(available_space, cx); - } + active_drag.view.draw(available_space, cx); cx.active_drag = Some(active_drag); }); }); @@ -994,12 +992,12 @@ impl<'a, 'w> WindowContext<'a, 'w> { InputEvent::FileDrop(file_drop) => match file_drop { FileDropEvent::Entered { position, files } => { self.window.mouse_position = position; - self.active_drag.get_or_insert_with(|| AnyDrag { - drag_handle_view: None, - cursor_offset: position, - state: Box::new(files), - state_type: TypeId::of::(), - }); + if self.active_drag.is_none() { + self.active_drag = Some(AnyDrag { + view: self.build_view(|_| files).into_any(), + cursor_offset: position, + }); + } InputEvent::MouseDown(MouseDownEvent { position, button: MouseButton::Left, @@ -1267,30 +1265,30 @@ impl<'a, 'w> WindowContext<'a, 'w> { } impl Context for WindowContext<'_, '_> { - type EntityContext<'a, T> = ModelContext<'a, T>; + type ModelContext<'a, T> = ModelContext<'a, T>; type Result = T; - fn entity( + fn build_model( &mut self, - build_entity: impl FnOnce(&mut Self::EntityContext<'_, T>) -> T, - ) -> Handle + build_model: impl FnOnce(&mut Self::ModelContext<'_, T>) -> T, + ) -> Model where T: 'static + Send, { let slot = self.app.entities.reserve(); - let entity = build_entity(&mut ModelContext::mutable(&mut *self.app, slot.downgrade())); - self.entities.insert(slot, entity) + let model = build_model(&mut ModelContext::mutable(&mut *self.app, slot.downgrade())); + self.entities.insert(slot, model) } fn update_entity( &mut self, - handle: &Handle, - update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, T>) -> R, + model: &Model, + update: impl FnOnce(&mut T, &mut Self::ModelContext<'_, T>) -> R, ) -> R { - let mut entity = self.entities.lease(handle); + let mut entity = self.entities.lease(model); let result = update( &mut *entity, - &mut ModelContext::mutable(&mut *self.app, handle.downgrade()), + &mut ModelContext::mutable(&mut *self.app, model.downgrade()), ); self.entities.end_lease(entity); result @@ -1300,21 +1298,17 @@ impl Context for WindowContext<'_, '_> { impl VisualContext for WindowContext<'_, '_> { type ViewContext<'a, 'w, V> = ViewContext<'a, 'w, V>; - /// Builds a new view in the current window. The first argument is a function that builds - /// an entity representing the view's state. It is invoked with a `ViewContext` that provides - /// entity-specific access to the window and application state during construction. The second - /// argument is a render function that returns a component based on the view's state. - fn build_view( + fn build_view( &mut self, build_view_state: impl FnOnce(&mut Self::ViewContext<'_, '_, V>) -> V, - render: impl Fn(&mut V, &mut ViewContext<'_, '_, V>) -> E + Send + 'static, ) -> Self::Result> where - E: crate::Component, V: 'static + Send, { let slot = self.app.entities.reserve(); - let view = View::for_handle(slot.clone(), render); + let view = View { + model: slot.clone(), + }; let mut cx = ViewContext::mutable(&mut *self.app, &mut *self.window, view.downgrade()); let entity = build_view_state(&mut cx); self.entities.insert(slot, entity); @@ -1327,7 +1321,7 @@ impl VisualContext for WindowContext<'_, '_> { view: &View, update: impl FnOnce(&mut T, &mut Self::ViewContext<'_, '_, T>) -> R, ) -> Self::Result { - let mut lease = self.app.entities.lease(&view.state); + let mut lease = self.app.entities.lease(&view.model); let mut cx = ViewContext::mutable(&mut *self.app, &mut *self.window, view.downgrade()); let result = update(&mut *lease, &mut cx); cx.app.entities.end_lease(lease); @@ -1582,8 +1576,8 @@ impl<'a, 'w, V: 'static> ViewContext<'a, 'w, V> { self.view.clone() } - pub fn handle(&self) -> WeakHandle { - self.view.state.clone() + pub fn model(&self) -> WeakModel { + self.view.model.clone() } pub fn stack(&mut self, order: u32, f: impl FnOnce(&mut Self) -> R) -> R { @@ -1603,8 +1597,8 @@ impl<'a, 'w, V: 'static> ViewContext<'a, 'w, V> { pub fn observe( &mut self, - handle: &Handle, - mut on_notify: impl FnMut(&mut V, Handle, &mut ViewContext<'_, '_, V>) + Send + 'static, + handle: &Model, + mut on_notify: impl FnMut(&mut V, Model, &mut ViewContext<'_, '_, V>) + Send + 'static, ) -> Subscription where E: 'static, @@ -1665,7 +1659,7 @@ impl<'a, 'w, V: 'static> ViewContext<'a, 'w, V> { ) -> Subscription { let window_handle = self.window.handle; self.app.release_listeners.insert( - self.view.state.entity_id, + self.view.model.entity_id, Box::new(move |this, cx| { let this = this.downcast_mut().expect("invalid entity type"); // todo!("are we okay with silently swallowing the error?") @@ -1676,7 +1670,7 @@ impl<'a, 'w, V: 'static> ViewContext<'a, 'w, V> { pub fn observe_release( &mut self, - handle: &Handle, + handle: &Model, mut on_release: impl FnMut(&mut V, &mut T, &mut ViewContext<'_, '_, V>) + Send + 'static, ) -> Subscription where @@ -1698,7 +1692,7 @@ impl<'a, 'w, V: 'static> ViewContext<'a, 'w, V> { pub fn notify(&mut self) { self.window_cx.notify(); self.window_cx.app.push_effect(Effect::Notify { - emitter: self.view.state.entity_id, + emitter: self.view.model.entity_id, }); } @@ -1878,7 +1872,7 @@ where V::Event: Any + Send, { pub fn emit(&mut self, event: V::Event) { - let emitter = self.view.state.entity_id; + let emitter = self.view.model.entity_id; self.app.push_effect(Effect::Emit { emitter, event: Box::new(event), @@ -1897,41 +1891,36 @@ impl<'a, 'w, V: 'static> MainThread> { } impl<'a, 'w, V> Context for ViewContext<'a, 'w, V> { - type EntityContext<'b, U> = ModelContext<'b, U>; + type ModelContext<'b, U> = ModelContext<'b, U>; type Result = U; - fn entity( + fn build_model( &mut self, - build_entity: impl FnOnce(&mut Self::EntityContext<'_, T>) -> T, - ) -> Handle + build_model: impl FnOnce(&mut Self::ModelContext<'_, T>) -> T, + ) -> Model where T: 'static + Send, { - self.window_cx.entity(build_entity) + self.window_cx.build_model(build_model) } fn update_entity( &mut self, - handle: &Handle, - update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, T>) -> R, + model: &Model, + update: impl FnOnce(&mut T, &mut Self::ModelContext<'_, T>) -> R, ) -> R { - self.window_cx.update_entity(handle, update) + self.window_cx.update_entity(model, update) } } impl VisualContext for ViewContext<'_, '_, V> { type ViewContext<'a, 'w, V2> = ViewContext<'a, 'w, V2>; - fn build_view( + fn build_view( &mut self, - build_entity: impl FnOnce(&mut Self::ViewContext<'_, '_, V2>) -> V2, - render: impl Fn(&mut V2, &mut ViewContext<'_, '_, V2>) -> E + Send + 'static, - ) -> Self::Result> - where - E: crate::Component, - V2: 'static + Send, - { - self.window_cx.build_view(build_entity, render) + build_view: impl FnOnce(&mut Self::ViewContext<'_, '_, W>) -> W, + ) -> Self::Result> { + self.window_cx.build_view(build_view) } fn update_view( diff --git a/crates/language2/src/buffer_tests.rs b/crates/language2/src/buffer_tests.rs index fc60f31018..d2d886dd84 100644 --- a/crates/language2/src/buffer_tests.rs +++ b/crates/language2/src/buffer_tests.rs @@ -5,7 +5,7 @@ use crate::language_settings::{ use crate::Buffer; use clock::ReplicaId; use collections::BTreeMap; -use gpui2::{AppContext, Handle}; +use gpui2::{AppContext, Model}; use gpui2::{Context, TestAppContext}; use indoc::indoc; use proto::deserialize_operation; @@ -42,7 +42,7 @@ fn init_logger() { fn test_line_endings(cx: &mut gpui2::AppContext) { init_settings(cx, |_| {}); - cx.entity(|cx| { + cx.build_model(|cx| { let mut buffer = Buffer::new(0, cx.entity_id().as_u64(), "one\r\ntwo\rthree") .with_language(Arc::new(rust_lang()), cx); assert_eq!(buffer.text(), "one\ntwo\nthree"); @@ -138,8 +138,8 @@ fn test_edit_events(cx: &mut gpui2::AppContext) { let buffer_1_events = Arc::new(Mutex::new(Vec::new())); let buffer_2_events = Arc::new(Mutex::new(Vec::new())); - let buffer1 = cx.entity(|cx| Buffer::new(0, cx.entity_id().as_u64(), "abcdef")); - let buffer2 = cx.entity(|cx| Buffer::new(1, cx.entity_id().as_u64(), "abcdef")); + let buffer1 = cx.build_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), "abcdef")); + let buffer2 = cx.build_model(|cx| Buffer::new(1, cx.entity_id().as_u64(), "abcdef")); let buffer1_ops = Arc::new(Mutex::new(Vec::new())); buffer1.update(cx, { let buffer1_ops = buffer1_ops.clone(); @@ -218,7 +218,7 @@ fn test_edit_events(cx: &mut gpui2::AppContext) { #[gpui2::test] async fn test_apply_diff(cx: &mut TestAppContext) { let text = "a\nbb\nccc\ndddd\neeeee\nffffff\n"; - let buffer = cx.entity(|cx| Buffer::new(0, cx.entity_id().as_u64(), text)); + let buffer = cx.build_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), text)); let anchor = buffer.update(cx, |buffer, _| buffer.anchor_before(Point::new(3, 3))); let text = "a\nccc\ndddd\nffffff\n"; @@ -250,7 +250,7 @@ async fn test_normalize_whitespace(cx: &mut gpui2::TestAppContext) { ] .join("\n"); - let buffer = cx.entity(|cx| Buffer::new(0, cx.entity_id().as_u64(), text)); + let buffer = cx.build_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), text)); // Spawn a task to format the buffer's whitespace. // Pause so that the foratting task starts running. @@ -314,7 +314,7 @@ async fn test_normalize_whitespace(cx: &mut gpui2::TestAppContext) { #[gpui2::test] async fn test_reparse(cx: &mut gpui2::TestAppContext) { let text = "fn a() {}"; - let buffer = cx.entity(|cx| { + let buffer = cx.build_model(|cx| { Buffer::new(0, cx.entity_id().as_u64(), text).with_language(Arc::new(rust_lang()), cx) }); @@ -442,7 +442,7 @@ async fn test_reparse(cx: &mut gpui2::TestAppContext) { #[gpui2::test] async fn test_resetting_language(cx: &mut gpui2::TestAppContext) { - let buffer = cx.entity(|cx| { + let buffer = cx.build_model(|cx| { let mut buffer = Buffer::new(0, cx.entity_id().as_u64(), "{}").with_language(Arc::new(rust_lang()), cx); buffer.set_sync_parse_timeout(Duration::ZERO); @@ -492,7 +492,7 @@ async fn test_outline(cx: &mut gpui2::TestAppContext) { "# .unindent(); - let buffer = cx.entity(|cx| { + let buffer = cx.build_model(|cx| { Buffer::new(0, cx.entity_id().as_u64(), text).with_language(Arc::new(rust_lang()), cx) }); let outline = buffer @@ -578,7 +578,7 @@ async fn test_outline_nodes_with_newlines(cx: &mut gpui2::TestAppContext) { "# .unindent(); - let buffer = cx.entity(|cx| { + let buffer = cx.build_model(|cx| { Buffer::new(0, cx.entity_id().as_u64(), text).with_language(Arc::new(rust_lang()), cx) }); let outline = buffer @@ -616,7 +616,7 @@ async fn test_outline_with_extra_context(cx: &mut gpui2::TestAppContext) { "# .unindent(); - let buffer = cx.entity(|cx| { + let buffer = cx.build_model(|cx| { Buffer::new(0, cx.entity_id().as_u64(), text).with_language(Arc::new(language), cx) }); let snapshot = buffer.update(cx, |buffer, _| buffer.snapshot()); @@ -660,7 +660,7 @@ async fn test_symbols_containing(cx: &mut gpui2::TestAppContext) { "# .unindent(); - let buffer = cx.entity(|cx| { + let buffer = cx.build_model(|cx| { Buffer::new(0, cx.entity_id().as_u64(), text).with_language(Arc::new(rust_lang()), cx) }); let snapshot = buffer.update(cx, |buffer, _| buffer.snapshot()); @@ -881,7 +881,7 @@ fn test_enclosing_bracket_ranges_where_brackets_are_not_outermost_children(cx: & #[gpui2::test] fn test_range_for_syntax_ancestor(cx: &mut AppContext) { - cx.entity(|cx| { + cx.build_model(|cx| { let text = "fn a() { b(|c| {}) }"; let buffer = Buffer::new(0, cx.entity_id().as_u64(), text).with_language(Arc::new(rust_lang()), cx); @@ -922,7 +922,7 @@ fn test_range_for_syntax_ancestor(cx: &mut AppContext) { fn test_autoindent_with_soft_tabs(cx: &mut AppContext) { init_settings(cx, |_| {}); - cx.entity(|cx| { + cx.build_model(|cx| { let text = "fn a() {}"; let mut buffer = Buffer::new(0, cx.entity_id().as_u64(), text).with_language(Arc::new(rust_lang()), cx); @@ -965,7 +965,7 @@ fn test_autoindent_with_hard_tabs(cx: &mut AppContext) { settings.defaults.hard_tabs = Some(true); }); - cx.entity(|cx| { + cx.build_model(|cx| { let text = "fn a() {}"; let mut buffer = Buffer::new(0, cx.entity_id().as_u64(), text).with_language(Arc::new(rust_lang()), cx); @@ -1006,7 +1006,7 @@ fn test_autoindent_with_hard_tabs(cx: &mut AppContext) { fn test_autoindent_does_not_adjust_lines_with_unchanged_suggestion(cx: &mut AppContext) { init_settings(cx, |_| {}); - cx.entity(|cx| { + cx.build_model(|cx| { let entity_id = cx.entity_id(); let mut buffer = Buffer::new( 0, @@ -1080,7 +1080,7 @@ fn test_autoindent_does_not_adjust_lines_with_unchanged_suggestion(cx: &mut AppC buffer }); - cx.entity(|cx| { + cx.build_model(|cx| { eprintln!("second buffer: {:?}", cx.entity_id()); let mut buffer = Buffer::new( @@ -1147,7 +1147,7 @@ fn test_autoindent_does_not_adjust_lines_with_unchanged_suggestion(cx: &mut AppC fn test_autoindent_does_not_adjust_lines_within_newly_created_errors(cx: &mut AppContext) { init_settings(cx, |_| {}); - cx.entity(|cx| { + cx.build_model(|cx| { let mut buffer = Buffer::new( 0, cx.entity_id().as_u64(), @@ -1209,7 +1209,7 @@ fn test_autoindent_does_not_adjust_lines_within_newly_created_errors(cx: &mut Ap fn test_autoindent_adjusts_lines_when_only_text_changes(cx: &mut AppContext) { init_settings(cx, |_| {}); - cx.entity(|cx| { + cx.build_model(|cx| { let mut buffer = Buffer::new( 0, cx.entity_id().as_u64(), @@ -1266,7 +1266,7 @@ fn test_autoindent_adjusts_lines_when_only_text_changes(cx: &mut AppContext) { fn test_autoindent_with_edit_at_end_of_buffer(cx: &mut AppContext) { init_settings(cx, |_| {}); - cx.entity(|cx| { + cx.build_model(|cx| { let text = "a\nb"; let mut buffer = Buffer::new(0, cx.entity_id().as_u64(), text).with_language(Arc::new(rust_lang()), cx); @@ -1284,7 +1284,7 @@ fn test_autoindent_with_edit_at_end_of_buffer(cx: &mut AppContext) { fn test_autoindent_multi_line_insertion(cx: &mut AppContext) { init_settings(cx, |_| {}); - cx.entity(|cx| { + cx.build_model(|cx| { let text = " const a: usize = 1; fn b() { @@ -1326,7 +1326,7 @@ fn test_autoindent_multi_line_insertion(cx: &mut AppContext) { fn test_autoindent_block_mode(cx: &mut AppContext) { init_settings(cx, |_| {}); - cx.entity(|cx| { + cx.build_model(|cx| { let text = r#" fn a() { b(); @@ -1410,7 +1410,7 @@ fn test_autoindent_block_mode(cx: &mut AppContext) { fn test_autoindent_block_mode_without_original_indent_columns(cx: &mut AppContext) { init_settings(cx, |_| {}); - cx.entity(|cx| { + cx.build_model(|cx| { let text = r#" fn a() { if b() { @@ -1490,7 +1490,7 @@ fn test_autoindent_block_mode_without_original_indent_columns(cx: &mut AppContex fn test_autoindent_language_without_indents_query(cx: &mut AppContext) { init_settings(cx, |_| {}); - cx.entity(|cx| { + cx.build_model(|cx| { let text = " * one - a @@ -1559,7 +1559,7 @@ fn test_autoindent_with_injected_languages(cx: &mut AppContext) { language_registry.add(html_language.clone()); language_registry.add(javascript_language.clone()); - cx.entity(|cx| { + cx.build_model(|cx| { let (text, ranges) = marked_text_ranges( &"
ˇ @@ -1610,7 +1610,7 @@ fn test_autoindent_query_with_outdent_captures(cx: &mut AppContext) { settings.defaults.tab_size = Some(2.try_into().unwrap()); }); - cx.entity(|cx| { + cx.build_model(|cx| { let mut buffer = Buffer::new(0, cx.entity_id().as_u64(), "").with_language(Arc::new(ruby_lang()), cx); @@ -1653,7 +1653,7 @@ fn test_autoindent_query_with_outdent_captures(cx: &mut AppContext) { fn test_language_scope_at_with_javascript(cx: &mut AppContext) { init_settings(cx, |_| {}); - cx.entity(|cx| { + cx.build_model(|cx| { let language = Language::new( LanguageConfig { name: "JavaScript".into(), @@ -1742,7 +1742,7 @@ fn test_language_scope_at_with_javascript(cx: &mut AppContext) { fn test_language_scope_at_with_rust(cx: &mut AppContext) { init_settings(cx, |_| {}); - cx.entity(|cx| { + cx.build_model(|cx| { let language = Language::new( LanguageConfig { name: "Rust".into(), @@ -1810,7 +1810,7 @@ fn test_language_scope_at_with_rust(cx: &mut AppContext) { fn test_language_scope_at_with_combined_injections(cx: &mut AppContext) { init_settings(cx, |_| {}); - cx.entity(|cx| { + cx.build_model(|cx| { let text = r#"
    <% people.each do |person| %> @@ -1858,7 +1858,7 @@ fn test_language_scope_at_with_combined_injections(cx: &mut AppContext) { fn test_serialization(cx: &mut gpui2::AppContext) { let mut now = Instant::now(); - let buffer1 = cx.entity(|cx| { + let buffer1 = cx.build_model(|cx| { let mut buffer = Buffer::new(0, cx.entity_id().as_u64(), "abc"); buffer.edit([(3..3, "D")], None, cx); @@ -1881,7 +1881,7 @@ fn test_serialization(cx: &mut gpui2::AppContext) { let ops = cx .executor() .block(buffer1.read(cx).serialize_ops(None, cx)); - let buffer2 = cx.entity(|cx| { + let buffer2 = cx.build_model(|cx| { let mut buffer = Buffer::from_proto(1, state, None).unwrap(); buffer .apply_ops( @@ -1914,10 +1914,11 @@ fn test_random_collaboration(cx: &mut AppContext, mut rng: StdRng) { let mut replica_ids = Vec::new(); let mut buffers = Vec::new(); let network = Arc::new(Mutex::new(Network::new(rng.clone()))); - let base_buffer = cx.entity(|cx| Buffer::new(0, cx.entity_id().as_u64(), base_text.as_str())); + let base_buffer = + cx.build_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), base_text.as_str())); for i in 0..rng.gen_range(min_peers..=max_peers) { - let buffer = cx.entity(|cx| { + let buffer = cx.build_model(|cx| { let state = base_buffer.read(cx).to_proto(); let ops = cx .executor() @@ -2034,7 +2035,7 @@ fn test_random_collaboration(cx: &mut AppContext, mut rng: StdRng) { new_replica_id, replica_id ); - new_buffer = Some(cx.entity(|cx| { + new_buffer = Some(cx.build_model(|cx| { let mut new_buffer = Buffer::from_proto(new_replica_id, old_buffer_state, None).unwrap(); new_buffer @@ -2396,7 +2397,7 @@ fn javascript_lang() -> Language { .unwrap() } -fn get_tree_sexp(buffer: &Handle, cx: &mut gpui2::TestAppContext) -> String { +fn get_tree_sexp(buffer: &Model, cx: &mut gpui2::TestAppContext) -> String { buffer.update(cx, |buffer, _| { let snapshot = buffer.snapshot(); let layers = snapshot.syntax.layers(buffer.as_text_snapshot()); @@ -2412,7 +2413,7 @@ fn assert_bracket_pairs( cx: &mut AppContext, ) { let (expected_text, selection_ranges) = marked_text_ranges(selection_text, false); - let buffer = cx.entity(|cx| { + let buffer = cx.build_model(|cx| { Buffer::new(0, cx.entity_id().as_u64(), expected_text.clone()) .with_language(Arc::new(language), cx) }); diff --git a/crates/menu2/Cargo.toml b/crates/menu2/Cargo.toml new file mode 100644 index 0000000000..c366de6866 --- /dev/null +++ b/crates/menu2/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "menu2" +version = "0.1.0" +edition = "2021" +publish = false + +[lib] +path = "src/menu2.rs" +doctest = false + +[dependencies] +gpui2 = { path = "../gpui2" } diff --git a/crates/menu2/src/menu2.rs b/crates/menu2/src/menu2.rs new file mode 100644 index 0000000000..decd4aca22 --- /dev/null +++ b/crates/menu2/src/menu2.rs @@ -0,0 +1,25 @@ +// todo!(use actions! macro) + +#[derive(Clone, Debug, Default, PartialEq)] +pub struct Cancel; + +#[derive(Clone, Debug, Default, PartialEq)] +pub struct Confirm; + +#[derive(Clone, Debug, Default, PartialEq)] +pub struct SecondaryConfirm; + +#[derive(Clone, Debug, Default, PartialEq)] +pub struct SelectPrev; + +#[derive(Clone, Debug, Default, PartialEq)] +pub struct SelectNext; + +#[derive(Clone, Debug, Default, PartialEq)] +pub struct SelectFirst; + +#[derive(Clone, Debug, Default, PartialEq)] +pub struct SelectLast; + +#[derive(Clone, Debug, Default, PartialEq)] +pub struct ShowContextMenu; diff --git a/crates/prettier2/Cargo.toml b/crates/prettier2/Cargo.toml index 8defd40262..b98124f72c 100644 --- a/crates/prettier2/Cargo.toml +++ b/crates/prettier2/Cargo.toml @@ -16,7 +16,7 @@ client2 = { path = "../client2" } collections = { path = "../collections"} language2 = { path = "../language2" } gpui2 = { path = "../gpui2" } -fs = { path = "../fs" } +fs2 = { path = "../fs2" } lsp2 = { path = "../lsp2" } node_runtime = { path = "../node_runtime"} util = { path = "../util" } @@ -32,4 +32,4 @@ parking_lot.workspace = true [dev-dependencies] language2 = { path = "../language2", features = ["test-support"] } gpui2 = { path = "../gpui2", features = ["test-support"] } -fs = { path = "../fs", features = ["test-support"] } +fs2 = { path = "../fs2", features = ["test-support"] } diff --git a/crates/prettier2/src/prettier2.rs b/crates/prettier2/src/prettier2.rs index 874ed10b91..804aeab594 100644 --- a/crates/prettier2/src/prettier2.rs +++ b/crates/prettier2/src/prettier2.rs @@ -1,7 +1,7 @@ use anyhow::Context; use collections::{HashMap, HashSet}; -use fs::Fs; -use gpui2::{AsyncAppContext, Handle}; +use fs2::Fs; +use gpui2::{AsyncAppContext, Model}; use language2::{language_settings::language_settings, Buffer, BundledFormatter, Diff}; use lsp2::{LanguageServer, LanguageServerId}; use node_runtime::NodeRuntime; @@ -183,7 +183,7 @@ impl Prettier { pub async fn format( &self, - buffer: &Handle, + buffer: &Model, buffer_path: Option, cx: &mut AsyncAppContext, ) -> anyhow::Result { diff --git a/crates/project2/Cargo.toml b/crates/project2/Cargo.toml index 98bf9b62be..b135b5367c 100644 --- a/crates/project2/Cargo.toml +++ b/crates/project2/Cargo.toml @@ -25,7 +25,7 @@ client2 = { path = "../client2" } clock = { path = "../clock" } collections = { path = "../collections" } db2 = { path = "../db2" } -fs = { path = "../fs" } +fs2 = { path = "../fs2" } fsevent = { path = "../fsevent" } fuzzy2 = { path = "../fuzzy2" } git = { path = "../git" } @@ -71,7 +71,7 @@ pretty_assertions.workspace = true client2 = { path = "../client2", features = ["test-support"] } collections = { path = "../collections", features = ["test-support"] } db2 = { path = "../db2", features = ["test-support"] } -fs = { path = "../fs", features = ["test-support"] } +fs2 = { path = "../fs2", features = ["test-support"] } gpui2 = { path = "../gpui2", features = ["test-support"] } language2 = { path = "../language2", features = ["test-support"] } lsp2 = { path = "../lsp2", features = ["test-support"] } diff --git a/crates/project2/src/lsp_command.rs b/crates/project2/src/lsp_command.rs index 3e5165b079..84a6c0517c 100644 --- a/crates/project2/src/lsp_command.rs +++ b/crates/project2/src/lsp_command.rs @@ -7,7 +7,7 @@ use anyhow::{anyhow, Context, Result}; use async_trait::async_trait; use client2::proto::{self, PeerId}; use futures::future; -use gpui2::{AppContext, AsyncAppContext, Handle}; +use gpui2::{AppContext, AsyncAppContext, Model}; use language2::{ language_settings::{language_settings, InlayHintKind}, point_from_lsp, point_to_lsp, @@ -53,8 +53,8 @@ pub(crate) trait LspCommand: 'static + Sized + Send { async fn response_from_lsp( self, message: ::Result, - project: Handle, - buffer: Handle, + project: Model, + buffer: Model, server_id: LanguageServerId, cx: AsyncAppContext, ) -> Result; @@ -63,8 +63,8 @@ pub(crate) trait LspCommand: 'static + Sized + Send { async fn from_proto( message: Self::ProtoRequest, - project: Handle, - buffer: Handle, + project: Model, + buffer: Model, cx: AsyncAppContext, ) -> Result; @@ -79,8 +79,8 @@ pub(crate) trait LspCommand: 'static + Sized + Send { async fn response_from_proto( self, message: ::Response, - project: Handle, - buffer: Handle, + project: Model, + buffer: Model, cx: AsyncAppContext, ) -> Result; @@ -180,8 +180,8 @@ impl LspCommand for PrepareRename { async fn response_from_lsp( self, message: Option, - _: Handle, - buffer: Handle, + _: Model, + buffer: Model, _: LanguageServerId, mut cx: AsyncAppContext, ) -> Result>> { @@ -215,8 +215,8 @@ impl LspCommand for PrepareRename { async fn from_proto( message: proto::PrepareRename, - _: Handle, - buffer: Handle, + _: Model, + buffer: Model, mut cx: AsyncAppContext, ) -> Result { let position = message @@ -256,8 +256,8 @@ impl LspCommand for PrepareRename { async fn response_from_proto( self, message: proto::PrepareRenameResponse, - _: Handle, - buffer: Handle, + _: Model, + buffer: Model, mut cx: AsyncAppContext, ) -> Result>> { if message.can_rename { @@ -307,8 +307,8 @@ impl LspCommand for PerformRename { async fn response_from_lsp( self, message: Option, - project: Handle, - buffer: Handle, + project: Model, + buffer: Model, server_id: LanguageServerId, mut cx: AsyncAppContext, ) -> Result { @@ -343,8 +343,8 @@ impl LspCommand for PerformRename { async fn from_proto( message: proto::PerformRename, - _: Handle, - buffer: Handle, + _: Model, + buffer: Model, mut cx: AsyncAppContext, ) -> Result { let position = message @@ -379,8 +379,8 @@ impl LspCommand for PerformRename { async fn response_from_proto( self, message: proto::PerformRenameResponse, - project: Handle, - _: Handle, + project: Model, + _: Model, mut cx: AsyncAppContext, ) -> Result { let message = message @@ -426,8 +426,8 @@ impl LspCommand for GetDefinition { async fn response_from_lsp( self, message: Option, - project: Handle, - buffer: Handle, + project: Model, + buffer: Model, server_id: LanguageServerId, cx: AsyncAppContext, ) -> Result> { @@ -447,8 +447,8 @@ impl LspCommand for GetDefinition { async fn from_proto( message: proto::GetDefinition, - _: Handle, - buffer: Handle, + _: Model, + buffer: Model, mut cx: AsyncAppContext, ) -> Result { let position = message @@ -479,8 +479,8 @@ impl LspCommand for GetDefinition { async fn response_from_proto( self, message: proto::GetDefinitionResponse, - project: Handle, - _: Handle, + project: Model, + _: Model, cx: AsyncAppContext, ) -> Result> { location_links_from_proto(message.links, project, cx).await @@ -527,8 +527,8 @@ impl LspCommand for GetTypeDefinition { async fn response_from_lsp( self, message: Option, - project: Handle, - buffer: Handle, + project: Model, + buffer: Model, server_id: LanguageServerId, cx: AsyncAppContext, ) -> Result> { @@ -548,8 +548,8 @@ impl LspCommand for GetTypeDefinition { async fn from_proto( message: proto::GetTypeDefinition, - _: Handle, - buffer: Handle, + _: Model, + buffer: Model, mut cx: AsyncAppContext, ) -> Result { let position = message @@ -580,8 +580,8 @@ impl LspCommand for GetTypeDefinition { async fn response_from_proto( self, message: proto::GetTypeDefinitionResponse, - project: Handle, - _: Handle, + project: Model, + _: Model, cx: AsyncAppContext, ) -> Result> { location_links_from_proto(message.links, project, cx).await @@ -593,8 +593,8 @@ impl LspCommand for GetTypeDefinition { } fn language_server_for_buffer( - project: &Handle, - buffer: &Handle, + project: &Model, + buffer: &Model, server_id: LanguageServerId, cx: &mut AsyncAppContext, ) -> Result<(Arc, Arc)> { @@ -609,7 +609,7 @@ fn language_server_for_buffer( async fn location_links_from_proto( proto_links: Vec, - project: Handle, + project: Model, mut cx: AsyncAppContext, ) -> Result> { let mut links = Vec::new(); @@ -671,8 +671,8 @@ async fn location_links_from_proto( async fn location_links_from_lsp( message: Option, - project: Handle, - buffer: Handle, + project: Model, + buffer: Model, server_id: LanguageServerId, mut cx: AsyncAppContext, ) -> Result> { @@ -814,8 +814,8 @@ impl LspCommand for GetReferences { async fn response_from_lsp( self, locations: Option>, - project: Handle, - buffer: Handle, + project: Model, + buffer: Model, server_id: LanguageServerId, mut cx: AsyncAppContext, ) -> Result> { @@ -868,8 +868,8 @@ impl LspCommand for GetReferences { async fn from_proto( message: proto::GetReferences, - _: Handle, - buffer: Handle, + _: Model, + buffer: Model, mut cx: AsyncAppContext, ) -> Result { let position = message @@ -910,8 +910,8 @@ impl LspCommand for GetReferences { async fn response_from_proto( self, message: proto::GetReferencesResponse, - project: Handle, - _: Handle, + project: Model, + _: Model, mut cx: AsyncAppContext, ) -> Result> { let mut locations = Vec::new(); @@ -977,8 +977,8 @@ impl LspCommand for GetDocumentHighlights { async fn response_from_lsp( self, lsp_highlights: Option>, - _: Handle, - buffer: Handle, + _: Model, + buffer: Model, _: LanguageServerId, mut cx: AsyncAppContext, ) -> Result> { @@ -1016,8 +1016,8 @@ impl LspCommand for GetDocumentHighlights { async fn from_proto( message: proto::GetDocumentHighlights, - _: Handle, - buffer: Handle, + _: Model, + buffer: Model, mut cx: AsyncAppContext, ) -> Result { let position = message @@ -1060,8 +1060,8 @@ impl LspCommand for GetDocumentHighlights { async fn response_from_proto( self, message: proto::GetDocumentHighlightsResponse, - _: Handle, - buffer: Handle, + _: Model, + buffer: Model, mut cx: AsyncAppContext, ) -> Result> { let mut highlights = Vec::new(); @@ -1123,8 +1123,8 @@ impl LspCommand for GetHover { async fn response_from_lsp( self, message: Option, - _: Handle, - buffer: Handle, + _: Model, + buffer: Model, _: LanguageServerId, mut cx: AsyncAppContext, ) -> Result { @@ -1206,8 +1206,8 @@ impl LspCommand for GetHover { async fn from_proto( message: Self::ProtoRequest, - _: Handle, - buffer: Handle, + _: Model, + buffer: Model, mut cx: AsyncAppContext, ) -> Result { let position = message @@ -1272,8 +1272,8 @@ impl LspCommand for GetHover { async fn response_from_proto( self, message: proto::GetHoverResponse, - _: Handle, - buffer: Handle, + _: Model, + buffer: Model, mut cx: AsyncAppContext, ) -> Result { let contents: Vec<_> = message @@ -1341,8 +1341,8 @@ impl LspCommand for GetCompletions { async fn response_from_lsp( self, completions: Option, - _: Handle, - buffer: Handle, + _: Model, + buffer: Model, server_id: LanguageServerId, mut cx: AsyncAppContext, ) -> Result> { @@ -1484,8 +1484,8 @@ impl LspCommand for GetCompletions { async fn from_proto( message: proto::GetCompletions, - _: Handle, - buffer: Handle, + _: Model, + buffer: Model, mut cx: AsyncAppContext, ) -> Result { let version = deserialize_version(&message.version); @@ -1523,8 +1523,8 @@ impl LspCommand for GetCompletions { async fn response_from_proto( self, message: proto::GetCompletionsResponse, - _: Handle, - buffer: Handle, + _: Model, + buffer: Model, mut cx: AsyncAppContext, ) -> Result> { buffer @@ -1589,8 +1589,8 @@ impl LspCommand for GetCodeActions { async fn response_from_lsp( self, actions: Option, - _: Handle, - _: Handle, + _: Model, + _: Model, server_id: LanguageServerId, _: AsyncAppContext, ) -> Result> { @@ -1623,8 +1623,8 @@ impl LspCommand for GetCodeActions { async fn from_proto( message: proto::GetCodeActions, - _: Handle, - buffer: Handle, + _: Model, + buffer: Model, mut cx: AsyncAppContext, ) -> Result { let start = message @@ -1663,8 +1663,8 @@ impl LspCommand for GetCodeActions { async fn response_from_proto( self, message: proto::GetCodeActionsResponse, - _: Handle, - buffer: Handle, + _: Model, + buffer: Model, mut cx: AsyncAppContext, ) -> Result> { buffer @@ -1726,8 +1726,8 @@ impl LspCommand for OnTypeFormatting { async fn response_from_lsp( self, message: Option>, - project: Handle, - buffer: Handle, + project: Model, + buffer: Model, server_id: LanguageServerId, mut cx: AsyncAppContext, ) -> Result> { @@ -1763,8 +1763,8 @@ impl LspCommand for OnTypeFormatting { async fn from_proto( message: proto::OnTypeFormatting, - _: Handle, - buffer: Handle, + _: Model, + buffer: Model, mut cx: AsyncAppContext, ) -> Result { let position = message @@ -1805,8 +1805,8 @@ impl LspCommand for OnTypeFormatting { async fn response_from_proto( self, message: proto::OnTypeFormattingResponse, - _: Handle, - _: Handle, + _: Model, + _: Model, _: AsyncAppContext, ) -> Result> { let Some(transaction) = message.transaction else { @@ -1825,7 +1825,7 @@ impl LspCommand for OnTypeFormatting { impl InlayHints { pub async fn lsp_to_project_hint( lsp_hint: lsp2::InlayHint, - buffer_handle: &Handle, + buffer_handle: &Model, server_id: LanguageServerId, resolve_state: ResolveState, force_no_type_left_padding: bool, @@ -2230,8 +2230,8 @@ impl LspCommand for InlayHints { async fn response_from_lsp( self, message: Option>, - project: Handle, - buffer: Handle, + project: Model, + buffer: Model, server_id: LanguageServerId, mut cx: AsyncAppContext, ) -> anyhow::Result> { @@ -2286,8 +2286,8 @@ impl LspCommand for InlayHints { async fn from_proto( message: proto::InlayHints, - _: Handle, - buffer: Handle, + _: Model, + buffer: Model, mut cx: AsyncAppContext, ) -> Result { let start = message @@ -2326,8 +2326,8 @@ impl LspCommand for InlayHints { async fn response_from_proto( self, message: proto::InlayHintsResponse, - _: Handle, - buffer: Handle, + _: Model, + buffer: Model, mut cx: AsyncAppContext, ) -> anyhow::Result> { buffer diff --git a/crates/project2/src/project2.rs b/crates/project2/src/project2.rs index 9a3c2b34f2..c2ee171866 100644 --- a/crates/project2/src/project2.rs +++ b/crates/project2/src/project2.rs @@ -26,8 +26,8 @@ use futures::{ }; use globset::{Glob, GlobSet, GlobSetBuilder}; use gpui2::{ - AnyHandle, AppContext, AsyncAppContext, Context, EventEmitter, Executor, Handle, ModelContext, - Task, WeakHandle, + AnyModel, AppContext, AsyncAppContext, Context, EventEmitter, Executor, Model, ModelContext, + Task, WeakModel, }; use itertools::Itertools; use language2::{ @@ -89,7 +89,7 @@ use util::{ post_inc, ResultExt, TryFutureExt as _, }; -pub use fs::*; +pub use fs2::*; pub use worktree::*; const MAX_SERVER_REINSTALL_ATTEMPT_COUNT: u64 = 4; @@ -128,7 +128,7 @@ pub struct Project { next_entry_id: Arc, join_project_response_message_id: u32, next_diagnostic_group_id: usize, - user_store: Handle, + user_store: Model, fs: Arc, client_state: Option, collaborators: HashMap, @@ -140,20 +140,20 @@ pub struct Project { #[allow(clippy::type_complexity)] loading_buffers_by_path: HashMap< ProjectPath, - postage::watch::Receiver, Arc>>>, + postage::watch::Receiver, Arc>>>, >, #[allow(clippy::type_complexity)] loading_local_worktrees: - HashMap, Shared, Arc>>>>, + HashMap, Shared, Arc>>>>, opened_buffers: HashMap, local_buffer_ids_by_path: HashMap, local_buffer_ids_by_entry_id: HashMap, /// A mapping from a buffer ID to None means that we've started waiting for an ID but haven't finished loading it. /// Used for re-issuing buffer requests when peers temporarily disconnect - incomplete_remote_buffers: HashMap>>, + incomplete_remote_buffers: HashMap>>, buffer_snapshots: HashMap>>, // buffer_id -> server_id -> vec of snapshots buffers_being_formatted: HashSet, - buffers_needing_diff: HashSet>, + buffers_needing_diff: HashSet>, git_diff_debouncer: DelayedDebounced, nonce: u128, _maintain_buffer_languages: Task<()>, @@ -244,15 +244,15 @@ enum LocalProjectUpdate { } enum OpenBuffer { - Strong(Handle), - Weak(WeakHandle), + Strong(Model), + Weak(WeakModel), Operations(Vec), } #[derive(Clone)] enum WorktreeHandle { - Strong(Handle), - Weak(WeakHandle), + Strong(Model), + Weak(WeakModel), } enum ProjectClientState { @@ -344,7 +344,7 @@ pub struct DiagnosticSummary { #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Location { - pub buffer: Handle, + pub buffer: Model, pub range: Range, } @@ -457,7 +457,7 @@ impl Hover { } #[derive(Default)] -pub struct ProjectTransaction(pub HashMap, language2::Transaction>); +pub struct ProjectTransaction(pub HashMap, language2::Transaction>); impl DiagnosticSummary { fn new<'a, T: 'a>(diagnostics: impl IntoIterator>) -> Self { @@ -527,7 +527,7 @@ pub enum FormatTrigger { } struct ProjectLspAdapterDelegate { - project: Handle, + project: Model, http_client: Arc, } @@ -543,7 +543,7 @@ impl FormatTrigger { #[derive(Clone, Debug, PartialEq)] enum SearchMatchCandidate { OpenBuffer { - buffer: Handle, + buffer: Model, // This might be an unnamed file without representation on filesystem path: Option>, }, @@ -621,12 +621,12 @@ impl Project { pub fn local( client: Arc, node: Arc, - user_store: Handle, + user_store: Model, languages: Arc, fs: Arc, cx: &mut AppContext, - ) -> Handle { - cx.entity(|cx: &mut ModelContext| { + ) -> Model { + cx.build_model(|cx: &mut ModelContext| { let (tx, rx) = mpsc::unbounded(); cx.spawn(move |this, cx| Self::send_buffer_ordered_messages(this, rx, cx)) .detach(); @@ -687,11 +687,11 @@ impl Project { pub async fn remote( remote_id: u64, client: Arc, - user_store: Handle, + user_store: Model, languages: Arc, fs: Arc, mut cx: AsyncAppContext, - ) -> Result> { + ) -> Result> { client.authenticate_and_connect(true, &cx).await?; let subscription = client.subscribe_to_entity(remote_id)?; @@ -700,7 +700,7 @@ impl Project { project_id: remote_id, }) .await?; - let this = cx.entity(|cx| { + let this = cx.build_model(|cx| { let replica_id = response.payload.replica_id as ReplicaId; let mut worktrees = Vec::new(); @@ -981,7 +981,7 @@ impl Project { cx.notify(); } - pub fn buffer_for_id(&self, remote_id: u64) -> Option> { + pub fn buffer_for_id(&self, remote_id: u64) -> Option> { self.opened_buffers .get(&remote_id) .and_then(|buffer| buffer.upgrade()) @@ -995,11 +995,11 @@ impl Project { self.client.clone() } - pub fn user_store(&self) -> Handle { + pub fn user_store(&self) -> Model { self.user_store.clone() } - pub fn opened_buffers(&self) -> Vec> { + pub fn opened_buffers(&self) -> Vec> { self.opened_buffers .values() .filter_map(|b| b.upgrade()) @@ -1061,7 +1061,7 @@ impl Project { } /// Collect all worktrees, including ones that don't appear in the project panel - pub fn worktrees<'a>(&'a self) -> impl 'a + DoubleEndedIterator> { + pub fn worktrees<'a>(&'a self) -> impl 'a + DoubleEndedIterator> { self.worktrees .iter() .filter_map(move |worktree| worktree.upgrade()) @@ -1071,7 +1071,7 @@ impl Project { pub fn visible_worktrees<'a>( &'a self, cx: &'a AppContext, - ) -> impl 'a + DoubleEndedIterator> { + ) -> impl 'a + DoubleEndedIterator> { self.worktrees.iter().filter_map(|worktree| { worktree.upgrade().and_then(|worktree| { if worktree.read(cx).is_visible() { @@ -1088,7 +1088,7 @@ impl Project { .map(|tree| tree.read(cx).root_name()) } - pub fn worktree_for_id(&self, id: WorktreeId, cx: &AppContext) -> Option> { + pub fn worktree_for_id(&self, id: WorktreeId, cx: &AppContext) -> Option> { self.worktrees() .find(|worktree| worktree.read(cx).id() == id) } @@ -1097,7 +1097,7 @@ impl Project { &self, entry_id: ProjectEntryId, cx: &AppContext, - ) -> Option> { + ) -> Option> { self.worktrees() .find(|worktree| worktree.read(cx).contains_entry(entry_id)) } @@ -1652,12 +1652,12 @@ impl Project { text: &str, language: Option>, cx: &mut ModelContext, - ) -> Result> { + ) -> Result> { if self.is_remote() { return Err(anyhow!("creating buffers as a guest is not supported yet")); } let id = post_inc(&mut self.next_buffer_id); - let buffer = cx.entity(|cx| { + let buffer = cx.build_model(|cx| { Buffer::new(self.replica_id(), id, text).with_language( language.unwrap_or_else(|| language2::PLAIN_TEXT.clone()), cx, @@ -1671,7 +1671,7 @@ impl Project { &mut self, path: impl Into, cx: &mut ModelContext, - ) -> Task> { + ) -> Task> { let task = self.open_buffer(path, cx); cx.spawn(move |_, mut cx| async move { let buffer = task.await?; @@ -1681,7 +1681,7 @@ impl Project { })? .ok_or_else(|| anyhow!("no project entry"))?; - let buffer: &AnyHandle = &buffer; + let buffer: &AnyModel = &buffer; Ok((project_entry_id, buffer.clone())) }) } @@ -1690,7 +1690,7 @@ impl Project { &mut self, abs_path: impl AsRef, cx: &mut ModelContext, - ) -> Task>> { + ) -> Task>> { if let Some((worktree, relative_path)) = self.find_local_worktree(abs_path.as_ref(), cx) { self.open_buffer((worktree.read(cx).id(), relative_path), cx) } else { @@ -1702,7 +1702,7 @@ impl Project { &mut self, path: impl Into, cx: &mut ModelContext, - ) -> Task>> { + ) -> Task>> { let project_path = path.into(); let worktree = if let Some(worktree) = self.worktree_for_id(project_path.worktree_id, cx) { worktree @@ -1757,9 +1757,9 @@ impl Project { fn open_local_buffer_internal( &mut self, path: &Arc, - worktree: &Handle, + worktree: &Model, cx: &mut ModelContext, - ) -> Task>> { + ) -> Task>> { let buffer_id = post_inc(&mut self.next_buffer_id); let load_buffer = worktree.update(cx, |worktree, cx| { let worktree = worktree.as_local_mut().unwrap(); @@ -1775,9 +1775,9 @@ impl Project { fn open_remote_buffer_internal( &mut self, path: &Arc, - worktree: &Handle, + worktree: &Model, cx: &mut ModelContext, - ) -> Task>> { + ) -> Task>> { let rpc = self.client.clone(); let project_id = self.remote_id().unwrap(); let remote_worktree_id = worktree.read(cx).id(); @@ -1805,7 +1805,7 @@ impl Project { language_server_id: LanguageServerId, language_server_name: LanguageServerName, cx: &mut ModelContext, - ) -> Task>> { + ) -> Task>> { cx.spawn(move |this, mut cx| async move { let abs_path = abs_path .to_file_path() @@ -1843,7 +1843,7 @@ impl Project { &mut self, id: u64, cx: &mut ModelContext, - ) -> Task>> { + ) -> Task>> { if let Some(buffer) = self.buffer_for_id(id) { Task::ready(Ok(buffer)) } else if self.is_local() { @@ -1866,7 +1866,7 @@ impl Project { pub fn save_buffers( &self, - buffers: HashSet>, + buffers: HashSet>, cx: &mut ModelContext, ) -> Task> { cx.spawn(move |this, mut cx| async move { @@ -1881,7 +1881,7 @@ impl Project { pub fn save_buffer( &self, - buffer: Handle, + buffer: Model, cx: &mut ModelContext, ) -> Task> { let Some(file) = File::from_dyn(buffer.read(cx).file()) else { @@ -1897,7 +1897,7 @@ impl Project { pub fn save_buffer_as( &mut self, - buffer: Handle, + buffer: Model, abs_path: PathBuf, cx: &mut ModelContext, ) -> Task> { @@ -1933,7 +1933,7 @@ impl Project { &mut self, path: &ProjectPath, cx: &mut ModelContext, - ) -> Option> { + ) -> Option> { let worktree = self.worktree_for_id(path.worktree_id, cx)?; self.opened_buffers.values().find_map(|buffer| { let buffer = buffer.upgrade()?; @@ -1948,7 +1948,7 @@ impl Project { fn register_buffer( &mut self, - buffer: &Handle, + buffer: &Model, cx: &mut ModelContext, ) -> Result<()> { self.request_buffer_diff_recalculation(buffer, cx); @@ -2030,7 +2030,7 @@ impl Project { fn register_buffer_with_language_servers( &mut self, - buffer_handle: &Handle, + buffer_handle: &Model, cx: &mut ModelContext, ) { let buffer = buffer_handle.read(cx); @@ -2114,7 +2114,7 @@ impl Project { fn unregister_buffer_from_language_servers( &mut self, - buffer: &Handle, + buffer: &Model, old_file: &File, cx: &mut ModelContext, ) { @@ -2149,7 +2149,7 @@ impl Project { fn register_buffer_with_copilot( &self, - buffer_handle: &Handle, + buffer_handle: &Model, cx: &mut ModelContext, ) { if let Some(copilot) = Copilot::global(cx) { @@ -2158,7 +2158,7 @@ impl Project { } async fn send_buffer_ordered_messages( - this: WeakHandle, + this: WeakModel, rx: UnboundedReceiver, mut cx: AsyncAppContext, ) -> Result<()> { @@ -2166,7 +2166,7 @@ impl Project { let mut operations_by_buffer_id = HashMap::default(); async fn flush_operations( - this: &WeakHandle, + this: &WeakModel, operations_by_buffer_id: &mut HashMap>, needs_resync_with_host: &mut bool, is_local: bool, @@ -2267,7 +2267,7 @@ impl Project { fn on_buffer_event( &mut self, - buffer: Handle, + buffer: Model, event: &BufferEvent, cx: &mut ModelContext, ) -> Option<()> { @@ -2480,7 +2480,7 @@ impl Project { fn request_buffer_diff_recalculation( &mut self, - buffer: &Handle, + buffer: &Model, cx: &mut ModelContext, ) { self.buffers_needing_diff.insert(buffer.downgrade()); @@ -2676,7 +2676,7 @@ impl Project { fn detect_language_for_buffer( &mut self, - buffer_handle: &Handle, + buffer_handle: &Model, cx: &mut ModelContext, ) -> Option<()> { // If the buffer has a language, set it and start the language server if we haven't already. @@ -2694,7 +2694,7 @@ impl Project { pub fn set_language_for_buffer( &mut self, - buffer: &Handle, + buffer: &Model, new_language: Arc, cx: &mut ModelContext, ) { @@ -2735,7 +2735,7 @@ impl Project { fn start_language_servers( &mut self, - worktree: &Handle, + worktree: &Model, worktree_path: Arc, language: Arc, cx: &mut ModelContext, @@ -2931,7 +2931,7 @@ impl Project { } async fn setup_and_insert_language_server( - this: WeakHandle, + this: WeakModel, initialization_options: Option, pending_server: PendingLanguageServer, adapter: Arc, @@ -2970,7 +2970,7 @@ impl Project { } async fn setup_pending_language_server( - this: WeakHandle, + this: WeakModel, initialization_options: Option, pending_server: PendingLanguageServer, adapter: Arc, @@ -3350,10 +3350,10 @@ impl Project { pub fn restart_language_servers_for_buffers( &mut self, - buffers: impl IntoIterator>, + buffers: impl IntoIterator>, cx: &mut ModelContext, ) -> Option<()> { - let language_server_lookup_info: HashSet<(Handle, Arc)> = buffers + let language_server_lookup_info: HashSet<(Model, Arc)> = buffers .into_iter() .filter_map(|buffer| { let buffer = buffer.read(cx); @@ -3377,7 +3377,7 @@ impl Project { // TODO This will break in the case where the adapter's root paths and worktrees are not equal fn restart_language_servers( &mut self, - worktree: Handle, + worktree: Model, language: Arc, cx: &mut ModelContext, ) { @@ -3748,7 +3748,7 @@ impl Project { } async fn on_lsp_workspace_edit( - this: WeakHandle, + this: WeakModel, params: lsp2::ApplyWorkspaceEditParams, server_id: LanguageServerId, adapter: Arc, @@ -3949,7 +3949,7 @@ impl Project { fn update_buffer_diagnostics( &mut self, - buffer: &Handle, + buffer: &Model, server_id: LanguageServerId, version: Option, mut diagnostics: Vec>>, @@ -4022,7 +4022,7 @@ impl Project { pub fn reload_buffers( &self, - buffers: HashSet>, + buffers: HashSet>, push_to_history: bool, cx: &mut ModelContext, ) -> Task> { @@ -4088,7 +4088,7 @@ impl Project { pub fn format( &self, - buffers: HashSet>, + buffers: HashSet>, push_to_history: bool, trigger: FormatTrigger, cx: &mut ModelContext, @@ -4360,8 +4360,8 @@ impl Project { } async fn format_via_lsp( - this: &WeakHandle, - buffer: &Handle, + this: &WeakModel, + buffer: &Model, abs_path: &Path, language_server: &Arc, tab_size: NonZeroU32, @@ -4410,7 +4410,7 @@ impl Project { } async fn format_via_external_command( - buffer: &Handle, + buffer: &Model, buffer_abs_path: &Path, command: &str, arguments: &[String], @@ -4470,7 +4470,7 @@ impl Project { pub fn definition( &self, - buffer: &Handle, + buffer: &Model, position: T, cx: &mut ModelContext, ) -> Task>> { @@ -4485,7 +4485,7 @@ impl Project { pub fn type_definition( &self, - buffer: &Handle, + buffer: &Model, position: T, cx: &mut ModelContext, ) -> Task>> { @@ -4500,7 +4500,7 @@ impl Project { pub fn references( &self, - buffer: &Handle, + buffer: &Model, position: T, cx: &mut ModelContext, ) -> Task>> { @@ -4515,7 +4515,7 @@ impl Project { pub fn document_highlights( &self, - buffer: &Handle, + buffer: &Model, position: T, cx: &mut ModelContext, ) -> Task>> { @@ -4694,7 +4694,7 @@ impl Project { &mut self, symbol: &Symbol, cx: &mut ModelContext, - ) -> Task>> { + ) -> Task>> { if self.is_local() { let language_server_id = if let Some(id) = self.language_server_ids.get(&( symbol.source_worktree_id, @@ -4748,7 +4748,7 @@ impl Project { pub fn hover( &self, - buffer: &Handle, + buffer: &Model, position: T, cx: &mut ModelContext, ) -> Task>> { @@ -4763,7 +4763,7 @@ impl Project { pub fn completions( &self, - buffer: &Handle, + buffer: &Model, position: T, cx: &mut ModelContext, ) -> Task>> { @@ -4817,7 +4817,7 @@ impl Project { pub fn apply_additional_edits_for_completion( &self, - buffer_handle: Handle, + buffer_handle: Model, completion: Completion, push_to_history: bool, cx: &mut ModelContext, @@ -4928,7 +4928,7 @@ impl Project { pub fn code_actions( &self, - buffer_handle: &Handle, + buffer_handle: &Model, range: Range, cx: &mut ModelContext, ) -> Task>> { @@ -4944,7 +4944,7 @@ impl Project { pub fn apply_code_action( &self, - buffer_handle: Handle, + buffer_handle: Model, mut action: CodeAction, push_to_history: bool, cx: &mut ModelContext, @@ -5052,7 +5052,7 @@ impl Project { fn apply_on_type_formatting( &self, - buffer: Handle, + buffer: Model, position: Anchor, trigger: String, cx: &mut ModelContext, @@ -5113,8 +5113,8 @@ impl Project { } async fn deserialize_edits( - this: Handle, - buffer_to_edit: Handle, + this: Model, + buffer_to_edit: Model, edits: Vec, push_to_history: bool, _: Arc, @@ -5155,7 +5155,7 @@ impl Project { } async fn deserialize_workspace_edit( - this: Handle, + this: Model, edit: lsp2::WorkspaceEdit, push_to_history: bool, lsp_adapter: Arc, @@ -5201,7 +5201,7 @@ impl Project { fs.create_file( &abs_path, op.options - .map(|options| fs::CreateOptions { + .map(|options| fs2::CreateOptions { overwrite: options.overwrite.unwrap_or(false), ignore_if_exists: options.ignore_if_exists.unwrap_or(false), }) @@ -5224,7 +5224,7 @@ impl Project { &source_abs_path, &target_abs_path, op.options - .map(|options| fs::RenameOptions { + .map(|options| fs2::RenameOptions { overwrite: options.overwrite.unwrap_or(false), ignore_if_exists: options.ignore_if_exists.unwrap_or(false), }) @@ -5240,7 +5240,7 @@ impl Project { .map_err(|_| anyhow!("can't convert URI to path"))?; let options = op .options - .map(|options| fs::RemoveOptions { + .map(|options| fs2::RemoveOptions { recursive: options.recursive.unwrap_or(false), ignore_if_not_exists: options.ignore_if_not_exists.unwrap_or(false), }) @@ -5310,7 +5310,7 @@ impl Project { pub fn prepare_rename( &self, - buffer: Handle, + buffer: Model, position: T, cx: &mut ModelContext, ) -> Task>>> { @@ -5325,7 +5325,7 @@ impl Project { pub fn perform_rename( &self, - buffer: Handle, + buffer: Model, position: T, new_name: String, push_to_history: bool, @@ -5346,7 +5346,7 @@ impl Project { pub fn on_type_format( &self, - buffer: Handle, + buffer: Model, position: T, trigger: String, push_to_history: bool, @@ -5375,7 +5375,7 @@ impl Project { pub fn inlay_hints( &self, - buffer_handle: Handle, + buffer_handle: Model, range: Range, cx: &mut ModelContext, ) -> Task>> { @@ -5436,7 +5436,7 @@ impl Project { pub fn resolve_inlay_hint( &self, hint: InlayHint, - buffer_handle: Handle, + buffer_handle: Model, server_id: LanguageServerId, cx: &mut ModelContext, ) -> Task> { @@ -5501,7 +5501,7 @@ impl Project { &self, query: SearchQuery, cx: &mut ModelContext, - ) -> Receiver<(Handle, Vec>)> { + ) -> Receiver<(Model, Vec>)> { if self.is_local() { self.search_local(query, cx) } else if let Some(project_id) = self.remote_id() { @@ -5545,7 +5545,7 @@ impl Project { &self, query: SearchQuery, cx: &mut ModelContext, - ) -> Receiver<(Handle, Vec>)> { + ) -> Receiver<(Model, Vec>)> { // Local search is split into several phases. // TL;DR is that we do 2 passes; initial pass to pick files which contain at least one match // and the second phase that finds positions of all the matches found in the candidate files. @@ -5638,7 +5638,7 @@ impl Project { .scoped(|scope| { #[derive(Clone)] struct FinishedStatus { - entry: Option<(Handle, Vec>)>, + entry: Option<(Model, Vec>)>, buffer_index: SearchMatchCandidateIndex, } @@ -5728,8 +5728,8 @@ impl Project { /// Pick paths that might potentially contain a match of a given search query. async fn background_search( - unnamed_buffers: Vec>, - opened_buffers: HashMap, (Handle, BufferSnapshot)>, + unnamed_buffers: Vec>, + opened_buffers: HashMap, (Model, BufferSnapshot)>, executor: Executor, fs: Arc, workers: usize, @@ -5829,7 +5829,7 @@ impl Project { fn request_lsp( &self, - buffer_handle: Handle, + buffer_handle: Model, server: LanguageServerToQuery, request: R, cx: &mut ModelContext, @@ -5893,7 +5893,7 @@ impl Project { fn send_lsp_proto_request( &self, - buffer: Handle, + buffer: Model, project_id: u64, request: R, cx: &mut ModelContext<'_, Project>, @@ -5922,7 +5922,7 @@ impl Project { ) -> ( futures::channel::oneshot::Receiver>, Receiver<( - Option<(Handle, BufferSnapshot)>, + Option<(Model, BufferSnapshot)>, SearchMatchCandidateIndex, )>, ) { @@ -5976,7 +5976,7 @@ impl Project { abs_path: impl AsRef, visible: bool, cx: &mut ModelContext, - ) -> Task, PathBuf)>> { + ) -> Task, PathBuf)>> { let abs_path = abs_path.as_ref(); if let Some((tree, relative_path)) = self.find_local_worktree(abs_path, cx) { Task::ready(Ok((tree, relative_path))) @@ -5991,7 +5991,7 @@ impl Project { &self, abs_path: &Path, cx: &AppContext, - ) -> Option<(Handle, PathBuf)> { + ) -> Option<(Model, PathBuf)> { for tree in &self.worktrees { if let Some(tree) = tree.upgrade() { if let Some(relative_path) = tree @@ -6018,7 +6018,7 @@ impl Project { abs_path: impl AsRef, visible: bool, cx: &mut ModelContext, - ) -> Task>> { + ) -> Task>> { let fs = self.fs.clone(); let client = self.client.clone(); let next_entry_id = self.next_entry_id.clone(); @@ -6078,7 +6078,7 @@ impl Project { self.metadata_changed(cx); } - fn add_worktree(&mut self, worktree: &Handle, cx: &mut ModelContext) { + fn add_worktree(&mut self, worktree: &Model, cx: &mut ModelContext) { cx.observe(worktree, |_, _, cx| cx.notify()).detach(); if worktree.read(cx).is_local() { cx.subscribe(worktree, |this, worktree, event, cx| match event { @@ -6128,7 +6128,7 @@ impl Project { fn update_local_worktree_buffers( &mut self, - worktree_handle: &Handle, + worktree_handle: &Model, changes: &[(Arc, ProjectEntryId, PathChange)], cx: &mut ModelContext, ) { @@ -6242,7 +6242,7 @@ impl Project { fn update_local_worktree_language_servers( &mut self, - worktree_handle: &Handle, + worktree_handle: &Model, changes: &[(Arc, ProjectEntryId, PathChange)], cx: &mut ModelContext, ) { @@ -6304,7 +6304,7 @@ impl Project { fn update_local_worktree_buffers_git_repos( &mut self, - worktree_handle: Handle, + worktree_handle: Model, changed_repos: &UpdatedGitRepositoriesSet, cx: &mut ModelContext, ) { @@ -6407,7 +6407,7 @@ impl Project { fn update_local_worktree_settings( &mut self, - worktree: &Handle, + worktree: &Model, changes: &UpdatedEntriesSet, cx: &mut ModelContext, ) { @@ -6473,7 +6473,7 @@ impl Project { fn update_prettier_settings( &self, - worktree: &Handle, + worktree: &Model, changes: &[(Arc, ProjectEntryId, PathChange)], cx: &mut ModelContext<'_, Project>, ) { @@ -6636,7 +6636,7 @@ impl Project { // RPC message handlers async fn handle_unshare_project( - this: Handle, + this: Model, _: TypedEnvelope, _: Arc, mut cx: AsyncAppContext, @@ -6652,7 +6652,7 @@ impl Project { } async fn handle_add_collaborator( - this: Handle, + this: Model, mut envelope: TypedEnvelope, _: Arc, mut cx: AsyncAppContext, @@ -6676,7 +6676,7 @@ impl Project { } async fn handle_update_project_collaborator( - this: Handle, + this: Model, envelope: TypedEnvelope, _: Arc, mut cx: AsyncAppContext, @@ -6726,7 +6726,7 @@ impl Project { } async fn handle_remove_collaborator( - this: Handle, + this: Model, envelope: TypedEnvelope, _: Arc, mut cx: AsyncAppContext, @@ -6755,7 +6755,7 @@ impl Project { } async fn handle_update_project( - this: Handle, + this: Model, envelope: TypedEnvelope, _: Arc, mut cx: AsyncAppContext, @@ -6770,7 +6770,7 @@ impl Project { } async fn handle_update_worktree( - this: Handle, + this: Model, envelope: TypedEnvelope, _: Arc, mut cx: AsyncAppContext, @@ -6788,7 +6788,7 @@ impl Project { } async fn handle_update_worktree_settings( - this: Handle, + this: Model, envelope: TypedEnvelope, _: Arc, mut cx: AsyncAppContext, @@ -6812,7 +6812,7 @@ impl Project { } async fn handle_create_project_entry( - this: Handle, + this: Model, envelope: TypedEnvelope, _: Arc, mut cx: AsyncAppContext, @@ -6837,7 +6837,7 @@ impl Project { } async fn handle_rename_project_entry( - this: Handle, + this: Model, envelope: TypedEnvelope, _: Arc, mut cx: AsyncAppContext, @@ -6865,7 +6865,7 @@ impl Project { } async fn handle_copy_project_entry( - this: Handle, + this: Model, envelope: TypedEnvelope, _: Arc, mut cx: AsyncAppContext, @@ -6893,7 +6893,7 @@ impl Project { } async fn handle_delete_project_entry( - this: Handle, + this: Model, envelope: TypedEnvelope, _: Arc, mut cx: AsyncAppContext, @@ -6923,7 +6923,7 @@ impl Project { } async fn handle_expand_project_entry( - this: Handle, + this: Model, envelope: TypedEnvelope, _: Arc, mut cx: AsyncAppContext, @@ -6946,7 +6946,7 @@ impl Project { } async fn handle_update_diagnostic_summary( - this: Handle, + this: Model, envelope: TypedEnvelope, _: Arc, mut cx: AsyncAppContext, @@ -6976,7 +6976,7 @@ impl Project { } async fn handle_start_language_server( - this: Handle, + this: Model, envelope: TypedEnvelope, _: Arc, mut cx: AsyncAppContext, @@ -7001,7 +7001,7 @@ impl Project { } async fn handle_update_language_server( - this: Handle, + this: Model, envelope: TypedEnvelope, _: Arc, mut cx: AsyncAppContext, @@ -7058,7 +7058,7 @@ impl Project { } async fn handle_update_buffer( - this: Handle, + this: Model, envelope: TypedEnvelope, _: Arc, mut cx: AsyncAppContext, @@ -7094,7 +7094,7 @@ impl Project { } async fn handle_create_buffer_for_peer( - this: Handle, + this: Model, envelope: TypedEnvelope, _: Arc, mut cx: AsyncAppContext, @@ -7117,7 +7117,7 @@ impl Project { } let buffer_id = state.id; - let buffer = cx.entity(|_| { + let buffer = cx.build_model(|_| { Buffer::from_proto(this.replica_id(), state, buffer_file).unwrap() }); this.incomplete_remote_buffers @@ -7154,7 +7154,7 @@ impl Project { } async fn handle_update_diff_base( - this: Handle, + this: Model, envelope: TypedEnvelope, _: Arc, mut cx: AsyncAppContext, @@ -7180,7 +7180,7 @@ impl Project { } async fn handle_update_buffer_file( - this: Handle, + this: Model, envelope: TypedEnvelope, _: Arc, mut cx: AsyncAppContext, @@ -7215,7 +7215,7 @@ impl Project { } async fn handle_save_buffer( - this: Handle, + this: Model, envelope: TypedEnvelope, _: Arc, mut cx: AsyncAppContext, @@ -7251,7 +7251,7 @@ impl Project { } async fn handle_reload_buffers( - this: Handle, + this: Model, envelope: TypedEnvelope, _: Arc, mut cx: AsyncAppContext, @@ -7280,7 +7280,7 @@ impl Project { } async fn handle_synchronize_buffers( - this: Handle, + this: Model, envelope: TypedEnvelope, _: Arc, mut cx: AsyncAppContext, @@ -7373,7 +7373,7 @@ impl Project { } async fn handle_format_buffers( - this: Handle, + this: Model, envelope: TypedEnvelope, _: Arc, mut cx: AsyncAppContext, @@ -7403,7 +7403,7 @@ impl Project { } async fn handle_apply_additional_edits_for_completion( - this: Handle, + this: Model, envelope: TypedEnvelope, _: Arc, mut cx: AsyncAppContext, @@ -7440,7 +7440,7 @@ impl Project { } async fn handle_apply_code_action( - this: Handle, + this: Model, envelope: TypedEnvelope, _: Arc, mut cx: AsyncAppContext, @@ -7471,7 +7471,7 @@ impl Project { } async fn handle_on_type_formatting( - this: Handle, + this: Model, envelope: TypedEnvelope, _: Arc, mut cx: AsyncAppContext, @@ -7503,7 +7503,7 @@ impl Project { } async fn handle_inlay_hints( - this: Handle, + this: Model, envelope: TypedEnvelope, _: Arc, mut cx: AsyncAppContext, @@ -7553,7 +7553,7 @@ impl Project { } async fn handle_resolve_inlay_hint( - this: Handle, + this: Model, envelope: TypedEnvelope, _: Arc, mut cx: AsyncAppContext, @@ -7587,7 +7587,7 @@ impl Project { } async fn handle_refresh_inlay_hints( - this: Handle, + this: Model, _: TypedEnvelope, _: Arc, mut cx: AsyncAppContext, @@ -7599,7 +7599,7 @@ impl Project { } async fn handle_lsp_command( - this: Handle, + this: Model, envelope: TypedEnvelope, _: Arc, mut cx: AsyncAppContext, @@ -7641,7 +7641,7 @@ impl Project { } async fn handle_get_project_symbols( - this: Handle, + this: Model, envelope: TypedEnvelope, _: Arc, mut cx: AsyncAppContext, @@ -7658,7 +7658,7 @@ impl Project { } async fn handle_search_project( - this: Handle, + this: Model, envelope: TypedEnvelope, _: Arc, mut cx: AsyncAppContext, @@ -7689,7 +7689,7 @@ impl Project { } async fn handle_open_buffer_for_symbol( - this: Handle, + this: Model, envelope: TypedEnvelope, _: Arc, mut cx: AsyncAppContext, @@ -7730,7 +7730,7 @@ impl Project { } async fn handle_open_buffer_by_id( - this: Handle, + this: Model, envelope: TypedEnvelope, _: Arc, mut cx: AsyncAppContext, @@ -7749,7 +7749,7 @@ impl Project { } async fn handle_open_buffer_by_path( - this: Handle, + this: Model, envelope: TypedEnvelope, _: Arc, mut cx: AsyncAppContext, @@ -7834,7 +7834,7 @@ impl Project { fn create_buffer_for_peer( &mut self, - buffer: &Handle, + buffer: &Model, peer_id: proto::PeerId, cx: &mut AppContext, ) -> u64 { @@ -7851,7 +7851,7 @@ impl Project { &mut self, id: u64, cx: &mut ModelContext, - ) -> Task>> { + ) -> Task>> { let mut opened_buffer_rx = self.opened_buffer.1.clone(); cx.spawn(move |this, mut cx| async move { @@ -8108,7 +8108,7 @@ impl Project { } async fn handle_buffer_saved( - this: Handle, + this: Model, envelope: TypedEnvelope, _: Arc, mut cx: AsyncAppContext, @@ -8141,7 +8141,7 @@ impl Project { } async fn handle_buffer_reloaded( - this: Handle, + this: Model, envelope: TypedEnvelope, _: Arc, mut cx: AsyncAppContext, @@ -8180,7 +8180,7 @@ impl Project { #[allow(clippy::type_complexity)] fn edits_from_lsp( &mut self, - buffer: &Handle, + buffer: &Model, lsp_edits: impl 'static + Send + IntoIterator, server_id: LanguageServerId, version: Option, @@ -8284,7 +8284,7 @@ impl Project { fn buffer_snapshot_for_lsp_version( &mut self, - buffer: &Handle, + buffer: &Model, server_id: LanguageServerId, version: Option, cx: &AppContext, @@ -8402,7 +8402,7 @@ impl Project { fn prettier_instance_for_buffer( &mut self, - buffer: &Handle, + buffer: &Model, cx: &mut ModelContext, ) -> Task, Arc>>>>> { let buffer = buffer.read(cx); @@ -8638,7 +8638,7 @@ impl Project { } fn subscribe_for_copilot_events( - copilot: &Handle, + copilot: &Model, cx: &mut ModelContext<'_, Project>, ) -> gpui2::Subscription { cx.subscribe( @@ -8691,7 +8691,7 @@ fn glob_literal_prefix<'a>(glob: &'a str) -> &'a str { } impl WorktreeHandle { - pub fn upgrade(&self) -> Option> { + pub fn upgrade(&self) -> Option> { match self { WorktreeHandle::Strong(handle) => Some(handle.clone()), WorktreeHandle::Weak(handle) => handle.upgrade(), @@ -8707,7 +8707,7 @@ impl WorktreeHandle { } impl OpenBuffer { - pub fn upgrade(&self) -> Option> { + pub fn upgrade(&self) -> Option> { match self { OpenBuffer::Strong(handle) => Some(handle.clone()), OpenBuffer::Weak(handle) => handle.upgrade(), @@ -8871,8 +8871,8 @@ impl Item for Buffer { } async fn wait_for_loading_buffer( - mut receiver: postage::watch::Receiver, Arc>>>, -) -> Result, Arc> { + mut receiver: postage::watch::Receiver, Arc>>>, +) -> Result, Arc> { loop { if let Some(result) = receiver.borrow().as_ref() { match result { diff --git a/crates/project2/src/terminals.rs b/crates/project2/src/terminals.rs index f958142437..5cd62d5ae6 100644 --- a/crates/project2/src/terminals.rs +++ b/crates/project2/src/terminals.rs @@ -1,5 +1,5 @@ use crate::Project; -use gpui2::{AnyWindowHandle, Context, Handle, ModelContext, WeakHandle}; +use gpui2::{AnyWindowHandle, Context, Model, ModelContext, WeakModel}; use settings2::Settings; use std::path::{Path, PathBuf}; use terminal2::{ @@ -11,7 +11,7 @@ use terminal2::{ use std::os::unix::ffi::OsStrExt; pub struct Terminals { - pub(crate) local_handles: Vec>, + pub(crate) local_handles: Vec>, } impl Project { @@ -20,7 +20,7 @@ impl Project { working_directory: Option, window: AnyWindowHandle, cx: &mut ModelContext, - ) -> anyhow::Result> { + ) -> anyhow::Result> { if self.is_remote() { return Err(anyhow::anyhow!( "creating terminals as a guest is not supported yet" @@ -40,7 +40,7 @@ impl Project { |_, _| todo!("color_for_index"), ) .map(|builder| { - let terminal_handle = cx.entity(|cx| builder.subscribe(cx)); + let terminal_handle = cx.build_model(|cx| builder.subscribe(cx)); self.terminals .local_handles @@ -108,7 +108,7 @@ impl Project { fn activate_python_virtual_environment( &mut self, activate_script: Option, - terminal_handle: &Handle, + terminal_handle: &Model, cx: &mut ModelContext, ) { if let Some(activate_script) = activate_script { @@ -121,7 +121,7 @@ impl Project { } } - pub fn local_terminal_handles(&self) -> &Vec> { + pub fn local_terminal_handles(&self) -> &Vec> { &self.terminals.local_handles } } diff --git a/crates/project2/src/worktree.rs b/crates/project2/src/worktree.rs index c1b762640b..d73769cc00 100644 --- a/crates/project2/src/worktree.rs +++ b/crates/project2/src/worktree.rs @@ -6,7 +6,7 @@ use anyhow::{anyhow, Context as _, Result}; use client2::{proto, Client}; use clock::ReplicaId; use collections::{HashMap, HashSet, VecDeque}; -use fs::{ +use fs2::{ repository::{GitFileStatus, GitRepository, RepoPath}, Fs, }; @@ -22,7 +22,7 @@ use futures::{ use fuzzy2::CharBag; use git::{DOT_GIT, GITIGNORE}; use gpui2::{ - AppContext, AsyncAppContext, Context, EventEmitter, Executor, Handle, ModelContext, Task, + AppContext, AsyncAppContext, Context, EventEmitter, Executor, Model, ModelContext, Task, }; use language2::{ proto::{ @@ -292,7 +292,7 @@ impl Worktree { fs: Arc, next_entry_id: Arc, cx: &mut AsyncAppContext, - ) -> Result> { + ) -> Result> { // After determining whether the root entry is a file or a directory, populate the // snapshot's "root name", which will be used for the purpose of fuzzy matching. let abs_path = path.into(); @@ -301,7 +301,7 @@ impl Worktree { .await .context("failed to stat worktree path")?; - cx.entity(move |cx: &mut ModelContext| { + cx.build_model(move |cx: &mut ModelContext| { let root_name = abs_path .file_name() .map_or(String::new(), |f| f.to_string_lossy().to_string()); @@ -406,8 +406,8 @@ impl Worktree { worktree: proto::WorktreeMetadata, client: Arc, cx: &mut AppContext, - ) -> Handle { - cx.entity(|cx: &mut ModelContext| { + ) -> Model { + cx.build_model(|cx: &mut ModelContext| { let snapshot = Snapshot { id: WorktreeId(worktree.id as usize), abs_path: Arc::from(PathBuf::from(worktree.abs_path)), @@ -593,7 +593,7 @@ impl LocalWorktree { id: u64, path: &Path, cx: &mut ModelContext, - ) -> Task>> { + ) -> Task>> { let path = Arc::from(path); cx.spawn(move |this, mut cx| async move { let (file, contents, diff_base) = this @@ -603,7 +603,7 @@ impl LocalWorktree { .executor() .spawn(async move { text::Buffer::new(0, id, contents) }) .await; - cx.entity(|_| Buffer::build(text_buffer, diff_base, Some(Arc::new(file)))) + cx.build_model(|_| Buffer::build(text_buffer, diff_base, Some(Arc::new(file)))) }) } @@ -920,7 +920,7 @@ impl LocalWorktree { pub fn save_buffer( &self, - buffer_handle: Handle, + buffer_handle: Model, path: Arc, has_changed_file: bool, cx: &mut ModelContext, @@ -1331,7 +1331,7 @@ impl RemoteWorktree { pub fn save_buffer( &self, - buffer_handle: Handle, + buffer_handle: Model, cx: &mut ModelContext, ) -> Task> { let buffer = buffer_handle.read(cx); @@ -2577,7 +2577,7 @@ impl fmt::Debug for Snapshot { #[derive(Clone, PartialEq)] pub struct File { - pub worktree: Handle, + pub worktree: Model, pub path: Arc, pub mtime: SystemTime, pub(crate) entry_id: ProjectEntryId, @@ -2701,7 +2701,7 @@ impl language2::LocalFile for File { } impl File { - pub fn for_entry(entry: Entry, worktree: Handle) -> Arc { + pub fn for_entry(entry: Entry, worktree: Model) -> Arc { Arc::new(Self { worktree, path: entry.path.clone(), @@ -2714,7 +2714,7 @@ impl File { pub fn from_proto( proto: rpc2::proto::File, - worktree: Handle, + worktree: Model, cx: &AppContext, ) -> Result { let worktree_id = worktree @@ -2815,7 +2815,7 @@ pub type UpdatedGitRepositoriesSet = Arc<[(Arc, GitRepositoryChange)]>; impl Entry { fn new( path: Arc, - metadata: &fs::Metadata, + metadata: &fs2::Metadata, next_entry_id: &AtomicUsize, root_char_bag: CharBag, ) -> Self { diff --git a/crates/semantic_index/Cargo.toml b/crates/semantic_index/Cargo.toml index 1febb2af78..875440ef3f 100644 --- a/crates/semantic_index/Cargo.toml +++ b/crates/semantic_index/Cargo.toml @@ -42,6 +42,7 @@ sha1 = "0.10.5" ndarray = { version = "0.15.0" } [dev-dependencies] +ai = { path = "../ai", features = ["test-support"] } collections = { path = "../collections", features = ["test-support"] } gpui = { path = "../gpui", features = ["test-support"] } language = { path = "../language", features = ["test-support"] } diff --git a/crates/semantic_index/src/embedding_queue.rs b/crates/semantic_index/src/embedding_queue.rs index d57d5c7bbe..6ae8faa4cd 100644 --- a/crates/semantic_index/src/embedding_queue.rs +++ b/crates/semantic_index/src/embedding_queue.rs @@ -41,7 +41,6 @@ pub struct EmbeddingQueue { pending_batch_token_count: usize, finished_files_tx: channel::Sender, finished_files_rx: channel::Receiver, - api_key: Option, } #[derive(Clone)] @@ -51,11 +50,7 @@ pub struct FileFragmentToEmbed { } impl EmbeddingQueue { - pub fn new( - embedding_provider: Arc, - executor: Arc, - api_key: Option, - ) -> Self { + pub fn new(embedding_provider: Arc, executor: Arc) -> Self { let (finished_files_tx, finished_files_rx) = channel::unbounded(); Self { embedding_provider, @@ -64,14 +59,9 @@ impl EmbeddingQueue { pending_batch_token_count: 0, finished_files_tx, finished_files_rx, - api_key, } } - pub fn set_api_key(&mut self, api_key: Option) { - self.api_key = api_key - } - pub fn push(&mut self, file: FileToEmbed) { if file.spans.is_empty() { self.finished_files_tx.try_send(file).unwrap(); @@ -118,7 +108,6 @@ impl EmbeddingQueue { let finished_files_tx = self.finished_files_tx.clone(); let embedding_provider = self.embedding_provider.clone(); - let api_key = self.api_key.clone(); self.executor .spawn(async move { @@ -143,7 +132,7 @@ impl EmbeddingQueue { return; }; - match embedding_provider.embed_batch(spans, api_key).await { + match embedding_provider.embed_batch(spans).await { Ok(embeddings) => { let mut embeddings = embeddings.into_iter(); for fragment in batch { diff --git a/crates/semantic_index/src/parsing.rs b/crates/semantic_index/src/parsing.rs index f9b8bac9a4..cb15ca453b 100644 --- a/crates/semantic_index/src/parsing.rs +++ b/crates/semantic_index/src/parsing.rs @@ -1,4 +1,7 @@ -use ai::embedding::{Embedding, EmbeddingProvider}; +use ai::{ + embedding::{Embedding, EmbeddingProvider}, + models::TruncationDirection, +}; use anyhow::{anyhow, Result}; use language::{Grammar, Language}; use rusqlite::{ @@ -108,7 +111,14 @@ impl CodeContextRetriever { .replace("", language_name.as_ref()) .replace("", &content); let digest = SpanDigest::from(document_span.as_str()); - let (document_span, token_count) = self.embedding_provider.truncate(&document_span); + let model = self.embedding_provider.base_model(); + let document_span = model.truncate( + &document_span, + model.capacity()?, + ai::models::TruncationDirection::End, + )?; + let token_count = model.count_tokens(&document_span)?; + Ok(vec![Span { range: 0..content.len(), content: document_span, @@ -131,7 +141,15 @@ impl CodeContextRetriever { ) .replace("", &content); let digest = SpanDigest::from(document_span.as_str()); - let (document_span, token_count) = self.embedding_provider.truncate(&document_span); + + let model = self.embedding_provider.base_model(); + let document_span = model.truncate( + &document_span, + model.capacity()?, + ai::models::TruncationDirection::End, + )?; + let token_count = model.count_tokens(&document_span)?; + Ok(vec![Span { range: 0..content.len(), content: document_span, @@ -222,8 +240,13 @@ impl CodeContextRetriever { .replace("", language_name.as_ref()) .replace("item", &span.content); - let (document_content, token_count) = - self.embedding_provider.truncate(&document_content); + let model = self.embedding_provider.base_model(); + let document_content = model.truncate( + &document_content, + model.capacity()?, + TruncationDirection::End, + )?; + let token_count = model.count_tokens(&document_content)?; span.content = document_content; span.token_count = token_count; diff --git a/crates/semantic_index/src/semantic_index.rs b/crates/semantic_index/src/semantic_index.rs index 8839d25a84..818faa0444 100644 --- a/crates/semantic_index/src/semantic_index.rs +++ b/crates/semantic_index/src/semantic_index.rs @@ -7,7 +7,8 @@ pub mod semantic_index_settings; mod semantic_index_tests; use crate::semantic_index_settings::SemanticIndexSettings; -use ai::embedding::{Embedding, EmbeddingProvider, OpenAIEmbeddings}; +use ai::embedding::{Embedding, EmbeddingProvider}; +use ai::providers::open_ai::OpenAIEmbeddingProvider; use anyhow::{anyhow, Result}; use collections::{BTreeMap, HashMap, HashSet}; use db::VectorDatabase; @@ -88,7 +89,7 @@ pub fn init( let semantic_index = SemanticIndex::new( fs, db_file_path, - Arc::new(OpenAIEmbeddings::new(http_client, cx.background())), + Arc::new(OpenAIEmbeddingProvider::new(http_client, cx.background())), language_registry, cx.clone(), ) @@ -123,8 +124,6 @@ pub struct SemanticIndex { _embedding_task: Task<()>, _parsing_files_tasks: Vec>, projects: HashMap, ProjectState>, - api_key: Option, - embedding_queue: Arc>, } struct ProjectState { @@ -278,18 +277,18 @@ impl SemanticIndex { } } - pub fn authenticate(&mut self, cx: &AppContext) { - if self.api_key.is_none() { - self.api_key = self.embedding_provider.retrieve_credentials(cx); - - self.embedding_queue - .lock() - .set_api_key(self.api_key.clone()); + pub fn authenticate(&mut self, cx: &AppContext) -> bool { + if !self.embedding_provider.has_credentials() { + self.embedding_provider.retrieve_credentials(cx); + } else { + return true; } + + self.embedding_provider.has_credentials() } pub fn is_authenticated(&self) -> bool { - self.api_key.is_some() + self.embedding_provider.has_credentials() } pub fn enabled(cx: &AppContext) -> bool { @@ -339,7 +338,7 @@ impl SemanticIndex { Ok(cx.add_model(|cx| { let t0 = Instant::now(); let embedding_queue = - EmbeddingQueue::new(embedding_provider.clone(), cx.background().clone(), None); + EmbeddingQueue::new(embedding_provider.clone(), cx.background().clone()); let _embedding_task = cx.background().spawn({ let embedded_files = embedding_queue.finished_files(); let db = db.clone(); @@ -404,8 +403,6 @@ impl SemanticIndex { _embedding_task, _parsing_files_tasks, projects: Default::default(), - api_key: None, - embedding_queue } })) } @@ -720,13 +717,13 @@ impl SemanticIndex { let index = self.index_project(project.clone(), cx); let embedding_provider = self.embedding_provider.clone(); - let api_key = self.api_key.clone(); cx.spawn(|this, mut cx| async move { index.await?; let t0 = Instant::now(); + let query = embedding_provider - .embed_batch(vec![query], api_key) + .embed_batch(vec![query]) .await? .pop() .ok_or_else(|| anyhow!("could not embed query"))?; @@ -944,7 +941,6 @@ impl SemanticIndex { let fs = self.fs.clone(); let db_path = self.db.path().clone(); let background = cx.background().clone(); - let api_key = self.api_key.clone(); cx.background().spawn(async move { let db = VectorDatabase::new(fs, db_path.clone(), background).await?; let mut results = Vec::::new(); @@ -959,15 +955,10 @@ impl SemanticIndex { .parse_file_with_template(None, &snapshot.text(), language) .log_err() .unwrap_or_default(); - if Self::embed_spans( - &mut spans, - embedding_provider.as_ref(), - &db, - api_key.clone(), - ) - .await - .log_err() - .is_some() + if Self::embed_spans(&mut spans, embedding_provider.as_ref(), &db) + .await + .log_err() + .is_some() { for span in spans { let similarity = span.embedding.unwrap().similarity(&query); @@ -1007,9 +998,8 @@ impl SemanticIndex { project: ModelHandle, cx: &mut ModelContext, ) -> Task> { - if self.api_key.is_none() { - self.authenticate(cx); - if self.api_key.is_none() { + if !self.is_authenticated() { + if !self.authenticate(cx) { return Task::ready(Err(anyhow!("user is not authenticated"))); } } @@ -1192,7 +1182,6 @@ impl SemanticIndex { spans: &mut [Span], embedding_provider: &dyn EmbeddingProvider, db: &VectorDatabase, - api_key: Option, ) -> Result<()> { let mut batch = Vec::new(); let mut batch_tokens = 0; @@ -1215,7 +1204,7 @@ impl SemanticIndex { if batch_tokens + span.token_count > embedding_provider.max_tokens_per_batch() { let batch_embeddings = embedding_provider - .embed_batch(mem::take(&mut batch), api_key.clone()) + .embed_batch(mem::take(&mut batch)) .await?; embeddings.extend(batch_embeddings); batch_tokens = 0; @@ -1227,7 +1216,7 @@ impl SemanticIndex { if !batch.is_empty() { let batch_embeddings = embedding_provider - .embed_batch(mem::take(&mut batch), api_key) + .embed_batch(mem::take(&mut batch)) .await?; embeddings.extend(batch_embeddings); diff --git a/crates/semantic_index/src/semantic_index_tests.rs b/crates/semantic_index/src/semantic_index_tests.rs index a1ee3e5ada..7a91d1e100 100644 --- a/crates/semantic_index/src/semantic_index_tests.rs +++ b/crates/semantic_index/src/semantic_index_tests.rs @@ -4,10 +4,9 @@ use crate::{ semantic_index_settings::SemanticIndexSettings, FileToEmbed, JobHandle, SearchResult, SemanticIndex, EMBEDDING_QUEUE_FLUSH_TIMEOUT, }; -use ai::embedding::{DummyEmbeddings, Embedding, EmbeddingProvider}; -use anyhow::Result; -use async_trait::async_trait; -use gpui::{executor::Deterministic, AppContext, Task, TestAppContext}; +use ai::test::FakeEmbeddingProvider; + +use gpui::{executor::Deterministic, Task, TestAppContext}; use language::{Language, LanguageConfig, LanguageRegistry, ToOffset}; use parking_lot::Mutex; use pretty_assertions::assert_eq; @@ -15,14 +14,7 @@ use project::{project_settings::ProjectSettings, search::PathMatcher, FakeFs, Fs use rand::{rngs::StdRng, Rng}; use serde_json::json; use settings::SettingsStore; -use std::{ - path::Path, - sync::{ - atomic::{self, AtomicUsize}, - Arc, - }, - time::{Instant, SystemTime}, -}; +use std::{path::Path, sync::Arc, time::SystemTime}; use unindent::Unindent; use util::RandomCharIter; @@ -228,7 +220,7 @@ async fn test_embedding_batching(cx: &mut TestAppContext, mut rng: StdRng) { let embedding_provider = Arc::new(FakeEmbeddingProvider::default()); - let mut queue = EmbeddingQueue::new(embedding_provider.clone(), cx.background(), None); + let mut queue = EmbeddingQueue::new(embedding_provider.clone(), cx.background()); for file in &files { queue.push(file.clone()); } @@ -280,7 +272,7 @@ fn assert_search_results( #[gpui::test] async fn test_code_context_retrieval_rust() { let language = rust_lang(); - let embedding_provider = Arc::new(DummyEmbeddings {}); + let embedding_provider = Arc::new(FakeEmbeddingProvider::default()); let mut retriever = CodeContextRetriever::new(embedding_provider); let text = " @@ -382,7 +374,7 @@ async fn test_code_context_retrieval_rust() { #[gpui::test] async fn test_code_context_retrieval_json() { let language = json_lang(); - let embedding_provider = Arc::new(DummyEmbeddings {}); + let embedding_provider = Arc::new(FakeEmbeddingProvider::default()); let mut retriever = CodeContextRetriever::new(embedding_provider); let text = r#" @@ -466,7 +458,7 @@ fn assert_documents_eq( #[gpui::test] async fn test_code_context_retrieval_javascript() { let language = js_lang(); - let embedding_provider = Arc::new(DummyEmbeddings {}); + let embedding_provider = Arc::new(FakeEmbeddingProvider::default()); let mut retriever = CodeContextRetriever::new(embedding_provider); let text = " @@ -565,7 +557,7 @@ async fn test_code_context_retrieval_javascript() { #[gpui::test] async fn test_code_context_retrieval_lua() { let language = lua_lang(); - let embedding_provider = Arc::new(DummyEmbeddings {}); + let embedding_provider = Arc::new(FakeEmbeddingProvider::default()); let mut retriever = CodeContextRetriever::new(embedding_provider); let text = r#" @@ -639,7 +631,7 @@ async fn test_code_context_retrieval_lua() { #[gpui::test] async fn test_code_context_retrieval_elixir() { let language = elixir_lang(); - let embedding_provider = Arc::new(DummyEmbeddings {}); + let embedding_provider = Arc::new(FakeEmbeddingProvider::default()); let mut retriever = CodeContextRetriever::new(embedding_provider); let text = r#" @@ -756,7 +748,7 @@ async fn test_code_context_retrieval_elixir() { #[gpui::test] async fn test_code_context_retrieval_cpp() { let language = cpp_lang(); - let embedding_provider = Arc::new(DummyEmbeddings {}); + let embedding_provider = Arc::new(FakeEmbeddingProvider::default()); let mut retriever = CodeContextRetriever::new(embedding_provider); let text = " @@ -909,7 +901,7 @@ async fn test_code_context_retrieval_cpp() { #[gpui::test] async fn test_code_context_retrieval_ruby() { let language = ruby_lang(); - let embedding_provider = Arc::new(DummyEmbeddings {}); + let embedding_provider = Arc::new(FakeEmbeddingProvider::default()); let mut retriever = CodeContextRetriever::new(embedding_provider); let text = r#" @@ -1100,7 +1092,7 @@ async fn test_code_context_retrieval_ruby() { #[gpui::test] async fn test_code_context_retrieval_php() { let language = php_lang(); - let embedding_provider = Arc::new(DummyEmbeddings {}); + let embedding_provider = Arc::new(FakeEmbeddingProvider::default()); let mut retriever = CodeContextRetriever::new(embedding_provider); let text = r#" @@ -1248,65 +1240,6 @@ async fn test_code_context_retrieval_php() { ); } -#[derive(Default)] -struct FakeEmbeddingProvider { - embedding_count: AtomicUsize, -} - -impl FakeEmbeddingProvider { - fn embedding_count(&self) -> usize { - self.embedding_count.load(atomic::Ordering::SeqCst) - } - - fn embed_sync(&self, span: &str) -> Embedding { - let mut result = vec![1.0; 26]; - for letter in span.chars() { - let letter = letter.to_ascii_lowercase(); - if letter as u32 >= 'a' as u32 { - let ix = (letter as u32) - ('a' as u32); - if ix < 26 { - result[ix as usize] += 1.0; - } - } - } - - let norm = result.iter().map(|x| x * x).sum::().sqrt(); - for x in &mut result { - *x /= norm; - } - - result.into() - } -} - -#[async_trait] -impl EmbeddingProvider for FakeEmbeddingProvider { - fn retrieve_credentials(&self, _cx: &AppContext) -> Option { - Some("Fake Credentials".to_string()) - } - fn truncate(&self, span: &str) -> (String, usize) { - (span.to_string(), 1) - } - - fn max_tokens_per_batch(&self) -> usize { - 200 - } - - fn rate_limit_expiration(&self) -> Option { - None - } - - async fn embed_batch( - &self, - spans: Vec, - _api_key: Option, - ) -> Result> { - self.embedding_count - .fetch_add(spans.len(), atomic::Ordering::SeqCst); - Ok(spans.iter().map(|span| self.embed_sync(span)).collect()) - } -} - fn js_lang() -> Arc { Arc::new( Language::new( diff --git a/crates/storybook2/src/stories.rs b/crates/storybook2/src/stories.rs index 2517522bc3..3d8a332fb9 100644 --- a/crates/storybook2/src/stories.rs +++ b/crates/storybook2/src/stories.rs @@ -1,9 +1,11 @@ +mod colors; mod focus; mod kitchen_sink; mod scroll; mod text; mod z_index; +pub use colors::*; pub use focus::*; pub use kitchen_sink::*; pub use scroll::*; diff --git a/crates/storybook2/src/stories/colors.rs b/crates/storybook2/src/stories/colors.rs new file mode 100644 index 0000000000..afc29660ff --- /dev/null +++ b/crates/storybook2/src/stories/colors.rs @@ -0,0 +1,38 @@ +use crate::story::Story; +use gpui2::{px, Div, Render}; +use ui::prelude::*; + +pub struct ColorsStory; + +impl Render for ColorsStory { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Self::Element { + let color_scales = theme2::default_color_scales(); + + Story::container(cx) + .child(Story::title(cx, "Colors")) + .child( + div() + .id("colors") + .flex() + .flex_col() + .gap_1() + .overflow_y_scroll() + .text_color(gpui2::white()) + .children(color_scales.into_iter().map(|(name, scale)| { + div() + .flex() + .child( + div() + .w(px(75.)) + .line_height(px(24.)) + .child(name.to_string()), + ) + .child(div().flex().gap_1().children( + (1..=12).map(|step| div().flex().size_6().bg(scale.step(cx, step))), + )) + })), + ) + } +} diff --git a/crates/storybook2/src/stories/focus.rs b/crates/storybook2/src/stories/focus.rs index aeb0a243b2..f3f6a8d5fb 100644 --- a/crates/storybook2/src/stories/focus.rs +++ b/crates/storybook2/src/stories/focus.rs @@ -1,9 +1,9 @@ -use crate::themes::rose_pine; use gpui2::{ - div, Focusable, KeyBinding, ParentElement, StatelessInteractive, Styled, View, VisualContext, - WindowContext, + div, Div, FocusEnabled, Focusable, KeyBinding, ParentElement, Render, StatefulInteraction, + StatelessInteractive, Styled, View, VisualContext, WindowContext, }; use serde::Deserialize; +use theme2::theme; #[derive(Clone, Default, PartialEq, Deserialize)] struct ActionA; @@ -14,12 +14,10 @@ struct ActionB; #[derive(Clone, Default, PartialEq, Deserialize)] struct ActionC; -pub struct FocusStory { - text: View<()>, -} +pub struct FocusStory {} impl FocusStory { - pub fn view(cx: &mut WindowContext) -> View<()> { + pub fn view(cx: &mut WindowContext) -> View { cx.bind_keys([ KeyBinding::new("cmd-a", ActionA, Some("parent")), KeyBinding::new("cmd-a", ActionB, Some("child-1")), @@ -27,91 +25,92 @@ impl FocusStory { ]); cx.register_action_type::(); cx.register_action_type::(); - let theme = rose_pine(); - let color_1 = theme.lowest.negative.default.foreground; - let color_2 = theme.lowest.positive.default.foreground; - let color_3 = theme.lowest.warning.default.foreground; - let color_4 = theme.lowest.accent.default.foreground; - let color_5 = theme.lowest.variant.default.foreground; - let color_6 = theme.highest.negative.default.foreground; + cx.build_view(move |cx| Self {}) + } +} + +impl Render for FocusStory { + type Element = Div, FocusEnabled>; + + fn render(&mut self, cx: &mut gpui2::ViewContext) -> Self::Element { + let theme = theme(cx); + let color_1 = theme.git_created; + let color_2 = theme.git_modified; + let color_3 = theme.git_deleted; + let color_4 = theme.git_conflict; + let color_5 = theme.git_ignored; + let color_6 = theme.git_renamed; let child_1 = cx.focus_handle(); let child_2 = cx.focus_handle(); - cx.build_view( - |_| (), - move |_, cx| { + div() + .id("parent") + .focusable() + .context("parent") + .on_action(|_, action: &ActionA, phase, cx| { + println!("Action A dispatched on parent during {:?}", phase); + }) + .on_action(|_, action: &ActionB, phase, cx| { + println!("Action B dispatched on parent during {:?}", phase); + }) + .on_focus(|_, _, _| println!("Parent focused")) + .on_blur(|_, _, _| println!("Parent blurred")) + .on_focus_in(|_, _, _| println!("Parent focus_in")) + .on_focus_out(|_, _, _| println!("Parent focus_out")) + .on_key_down(|_, event, phase, _| { + println!("Key down on parent {:?} {:?}", phase, event) + }) + .on_key_up(|_, event, phase, _| println!("Key up on parent {:?} {:?}", phase, event)) + .size_full() + .bg(color_1) + .focus(|style| style.bg(color_2)) + .focus_in(|style| style.bg(color_3)) + .child( div() - .id("parent") - .focusable() - .context("parent") - .on_action(|_, action: &ActionA, phase, cx| { - println!("Action A dispatched on parent during {:?}", phase); - }) + .track_focus(&child_1) + .context("child-1") .on_action(|_, action: &ActionB, phase, cx| { - println!("Action B dispatched on parent during {:?}", phase); + println!("Action B dispatched on child 1 during {:?}", phase); }) - .on_focus(|_, _, _| println!("Parent focused")) - .on_blur(|_, _, _| println!("Parent blurred")) - .on_focus_in(|_, _, _| println!("Parent focus_in")) - .on_focus_out(|_, _, _| println!("Parent focus_out")) + .w_full() + .h_6() + .bg(color_4) + .focus(|style| style.bg(color_5)) + .in_focus(|style| style.bg(color_6)) + .on_focus(|_, _, _| println!("Child 1 focused")) + .on_blur(|_, _, _| println!("Child 1 blurred")) + .on_focus_in(|_, _, _| println!("Child 1 focus_in")) + .on_focus_out(|_, _, _| println!("Child 1 focus_out")) .on_key_down(|_, event, phase, _| { - println!("Key down on parent {:?} {:?}", phase, event) + println!("Key down on child 1 {:?} {:?}", phase, event) }) .on_key_up(|_, event, phase, _| { - println!("Key up on parent {:?} {:?}", phase, event) + println!("Key up on child 1 {:?} {:?}", phase, event) }) - .size_full() - .bg(color_1) - .focus(|style| style.bg(color_2)) - .focus_in(|style| style.bg(color_3)) - .child( - div() - .track_focus(&child_1) - .context("child-1") - .on_action(|_, action: &ActionB, phase, cx| { - println!("Action B dispatched on child 1 during {:?}", phase); - }) - .w_full() - .h_6() - .bg(color_4) - .focus(|style| style.bg(color_5)) - .in_focus(|style| style.bg(color_6)) - .on_focus(|_, _, _| println!("Child 1 focused")) - .on_blur(|_, _, _| println!("Child 1 blurred")) - .on_focus_in(|_, _, _| println!("Child 1 focus_in")) - .on_focus_out(|_, _, _| println!("Child 1 focus_out")) - .on_key_down(|_, event, phase, _| { - println!("Key down on child 1 {:?} {:?}", phase, event) - }) - .on_key_up(|_, event, phase, _| { - println!("Key up on child 1 {:?} {:?}", phase, event) - }) - .child("Child 1"), - ) - .child( - div() - .track_focus(&child_2) - .context("child-2") - .on_action(|_, action: &ActionC, phase, cx| { - println!("Action C dispatched on child 2 during {:?}", phase); - }) - .w_full() - .h_6() - .bg(color_4) - .on_focus(|_, _, _| println!("Child 2 focused")) - .on_blur(|_, _, _| println!("Child 2 blurred")) - .on_focus_in(|_, _, _| println!("Child 2 focus_in")) - .on_focus_out(|_, _, _| println!("Child 2 focus_out")) - .on_key_down(|_, event, phase, _| { - println!("Key down on child 2 {:?} {:?}", phase, event) - }) - .on_key_up(|_, event, phase, _| { - println!("Key up on child 2 {:?} {:?}", phase, event) - }) - .child("Child 2"), - ) - }, - ) + .child("Child 1"), + ) + .child( + div() + .track_focus(&child_2) + .context("child-2") + .on_action(|_, action: &ActionC, phase, cx| { + println!("Action C dispatched on child 2 during {:?}", phase); + }) + .w_full() + .h_6() + .bg(color_4) + .on_focus(|_, _, _| println!("Child 2 focused")) + .on_blur(|_, _, _| println!("Child 2 blurred")) + .on_focus_in(|_, _, _| println!("Child 2 focus_in")) + .on_focus_out(|_, _, _| println!("Child 2 focus_out")) + .on_key_down(|_, event, phase, _| { + println!("Key down on child 2 {:?} {:?}", phase, event) + }) + .on_key_up(|_, event, phase, _| { + println!("Key up on child 2 {:?} {:?}", phase, event) + }) + .child("Child 2"), + ) } } diff --git a/crates/storybook2/src/stories/kitchen_sink.rs b/crates/storybook2/src/stories/kitchen_sink.rs index 3a4b127b55..cfa91417b6 100644 --- a/crates/storybook2/src/stories/kitchen_sink.rs +++ b/crates/storybook2/src/stories/kitchen_sink.rs @@ -1,26 +1,23 @@ -use gpui2::{AppContext, Context, View}; +use crate::{ + story::Story, + story_selector::{ComponentStory, ElementStory}, +}; +use gpui2::{Div, Render, StatefulInteraction, View, VisualContext}; use strum::IntoEnumIterator; use ui::prelude::*; -use crate::story::Story; -use crate::story_selector::{ComponentStory, ElementStory}; - -pub struct KitchenSinkStory {} +pub struct KitchenSinkStory; impl KitchenSinkStory { - pub fn new() -> Self { - Self {} + pub fn view(cx: &mut WindowContext) -> View { + cx.build_view(|cx| Self) } +} - pub fn view(cx: &mut AppContext) -> View { - { - let state = cx.entity(|cx| Self::new()); - let render = Self::render; - View::for_handle(state, render) - } - } +impl Render for KitchenSinkStory { + type Element = Div>; - fn render(&mut self, cx: &mut ViewContext) -> impl Component { + fn render(&mut self, cx: &mut ViewContext) -> Self::Element { let element_stories = ElementStory::iter() .map(|selector| selector.story(cx)) .collect::>(); diff --git a/crates/storybook2/src/stories/scroll.rs b/crates/storybook2/src/stories/scroll.rs index 662d44328b..b504a512a6 100644 --- a/crates/storybook2/src/stories/scroll.rs +++ b/crates/storybook2/src/stories/scroll.rs @@ -1,58 +1,54 @@ -use crate::themes::rose_pine; use gpui2::{ - div, px, Component, ParentElement, SharedString, Styled, View, VisualContext, WindowContext, + div, px, Component, Div, ParentElement, Render, SharedString, StatefulInteraction, Styled, + View, VisualContext, WindowContext, }; +use theme2::theme; -pub struct ScrollStory { - text: View<()>, -} +pub struct ScrollStory; impl ScrollStory { - pub fn view(cx: &mut WindowContext) -> View<()> { - let theme = rose_pine(); - - { - cx.build_view(|cx| (), move |_, cx| checkerboard(1)) - } + pub fn view(cx: &mut WindowContext) -> View { + cx.build_view(|cx| ScrollStory) } } -fn checkerboard(depth: usize) -> impl Component -where - S: 'static + Send + Sync, -{ - let theme = rose_pine(); - let color_1 = theme.lowest.positive.default.background; - let color_2 = theme.lowest.warning.default.background; +impl Render for ScrollStory { + type Element = Div>; - div() - .id("parent") - .bg(theme.lowest.base.default.background) - .size_full() - .overflow_scroll() - .children((0..10).map(|row| { - div() - .w(px(1000.)) - .h(px(100.)) - .flex() - .flex_row() - .children((0..10).map(|column| { - let id = SharedString::from(format!("{}, {}", row, column)); - let bg = if row % 2 == column % 2 { - color_1 - } else { - color_2 - }; - div().id(id).bg(bg).size(px(100. / depth as f32)).when( - row >= 5 && column >= 5, - |d| { - d.overflow_scroll() - .child(div().size(px(50.)).bg(color_1)) - .child(div().size(px(50.)).bg(color_2)) - .child(div().size(px(50.)).bg(color_1)) - .child(div().size(px(50.)).bg(color_2)) - }, - ) - })) - })) + fn render(&mut self, cx: &mut gpui2::ViewContext) -> Self::Element { + let theme = theme(cx); + let color_1 = theme.git_created; + let color_2 = theme.git_modified; + + div() + .id("parent") + .bg(theme.background) + .size_full() + .overflow_scroll() + .children((0..10).map(|row| { + div() + .w(px(1000.)) + .h(px(100.)) + .flex() + .flex_row() + .children((0..10).map(|column| { + let id = SharedString::from(format!("{}, {}", row, column)); + let bg = if row % 2 == column % 2 { + color_1 + } else { + color_2 + }; + div().id(id).bg(bg).size(px(100. as f32)).when( + row >= 5 && column >= 5, + |d| { + d.overflow_scroll() + .child(div().size(px(50.)).bg(color_1)) + .child(div().size(px(50.)).bg(color_2)) + .child(div().size(px(50.)).bg(color_1)) + .child(div().size(px(50.)).bg(color_2)) + }, + ) + })) + })) + } } diff --git a/crates/storybook2/src/stories/text.rs b/crates/storybook2/src/stories/text.rs index 20e109cfa0..85a9fd51a6 100644 --- a/crates/storybook2/src/stories/text.rs +++ b/crates/storybook2/src/stories/text.rs @@ -1,20 +1,21 @@ -use gpui2::{div, white, ParentElement, Styled, View, VisualContext, WindowContext}; +use gpui2::{div, white, Div, ParentElement, Render, Styled, View, VisualContext, WindowContext}; -pub struct TextStory { - text: View<()>, -} +pub struct TextStory; impl TextStory { - pub fn view(cx: &mut WindowContext) -> View<()> { - cx.build_view(|cx| (), |_, cx| { - div() - .size_full() - .bg(white()) - .child(concat!( - "The quick brown fox jumps over the lazy dog. ", - "Meanwhile, the lazy dog decided it was time for a change. ", - "He started daily workout routines, ate healthier and became the fastest dog in town.", - )) - }) + pub fn view(cx: &mut WindowContext) -> View { + cx.build_view(|cx| Self) + } +} + +impl Render for TextStory { + type Element = Div; + + fn render(&mut self, cx: &mut gpui2::ViewContext) -> Self::Element { + div().size_full().bg(white()).child(concat!( + "The quick brown fox jumps over the lazy dog. ", + "Meanwhile, the lazy dog decided it was time for a change. ", + "He started daily workout routines, ate healthier and became the fastest dog in town.", + )) } } diff --git a/crates/storybook2/src/stories/z_index.rs b/crates/storybook2/src/stories/z_index.rs index 7584d0b129..c0e1456bc0 100644 --- a/crates/storybook2/src/stories/z_index.rs +++ b/crates/storybook2/src/stories/z_index.rs @@ -1,15 +1,16 @@ -use gpui2::{px, rgb, Div, Hsla}; +use gpui2::{px, rgb, Div, Hsla, Render}; use ui::prelude::*; use crate::story::Story; /// A reimplementation of the MDN `z-index` example, found here: /// [https://developer.mozilla.org/en-US/docs/Web/CSS/z-index](https://developer.mozilla.org/en-US/docs/Web/CSS/z-index). -#[derive(Component)] pub struct ZIndexStory; -impl ZIndexStory { - fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { +impl Render for ZIndexStory { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Self::Element { Story::container(cx) .child(Story::title(cx, "z-index")) .child( diff --git a/crates/storybook2/src/story_selector.rs b/crates/storybook2/src/story_selector.rs index d6ff77c5c1..30d31f8cf3 100644 --- a/crates/storybook2/src/story_selector.rs +++ b/crates/storybook2/src/story_selector.rs @@ -7,13 +7,14 @@ use clap::builder::PossibleValue; use clap::ValueEnum; use gpui2::{AnyView, VisualContext}; use strum::{EnumIter, EnumString, IntoEnumIterator}; -use ui::prelude::*; +use ui::{prelude::*, AvatarStory, ButtonStory, DetailsStory, IconStory, InputStory, LabelStory}; #[derive(Debug, PartialEq, Eq, Clone, Copy, strum::Display, EnumString, EnumIter)] #[strum(serialize_all = "snake_case")] pub enum ElementStory { Avatar, Button, + Colors, Details, Focus, Icon, @@ -27,18 +28,17 @@ pub enum ElementStory { impl ElementStory { pub fn story(&self, cx: &mut WindowContext) -> AnyView { match self { - Self::Avatar => { cx.build_view(|cx| (), |_, _| ui::AvatarStory.render()) }.into_any(), - Self::Button => { cx.build_view(|cx| (), |_, _| ui::ButtonStory.render()) }.into_any(), - Self::Details => { - { cx.build_view(|cx| (), |_, _| ui::DetailsStory.render()) }.into_any() - } + Self::Colors => cx.build_view(|_| ColorsStory).into_any(), + Self::Avatar => cx.build_view(|_| AvatarStory).into_any(), + Self::Button => cx.build_view(|_| ButtonStory).into_any(), + Self::Details => cx.build_view(|_| DetailsStory).into_any(), Self::Focus => FocusStory::view(cx).into_any(), - Self::Icon => { cx.build_view(|cx| (), |_, _| ui::IconStory.render()) }.into_any(), - Self::Input => { cx.build_view(|cx| (), |_, _| ui::InputStory.render()) }.into_any(), - Self::Label => { cx.build_view(|cx| (), |_, _| ui::LabelStory.render()) }.into_any(), + Self::Icon => cx.build_view(|_| IconStory).into_any(), + Self::Input => cx.build_view(|_| InputStory).into_any(), + Self::Label => cx.build_view(|_| LabelStory).into_any(), Self::Scroll => ScrollStory::view(cx).into_any(), Self::Text => TextStory::view(cx).into_any(), - Self::ZIndex => { cx.build_view(|cx| (), |_, _| ZIndexStory.render()) }.into_any(), + Self::ZIndex => cx.build_view(|_| ZIndexStory).into_any(), } } } @@ -77,69 +77,31 @@ pub enum ComponentStory { impl ComponentStory { pub fn story(&self, cx: &mut WindowContext) -> AnyView { match self { - Self::AssistantPanel => { - { cx.build_view(|cx| (), |_, _| ui::AssistantPanelStory.render()) }.into_any() - } - Self::Buffer => { cx.build_view(|cx| (), |_, _| ui::BufferStory.render()) }.into_any(), - Self::Breadcrumb => { - { cx.build_view(|cx| (), |_, _| ui::BreadcrumbStory.render()) }.into_any() - } - Self::ChatPanel => { - { cx.build_view(|cx| (), |_, _| ui::ChatPanelStory.render()) }.into_any() - } - Self::CollabPanel => { - { cx.build_view(|cx| (), |_, _| ui::CollabPanelStory.render()) }.into_any() - } - Self::CommandPalette => { - { cx.build_view(|cx| (), |_, _| ui::CommandPaletteStory.render()) }.into_any() - } - Self::ContextMenu => { - { cx.build_view(|cx| (), |_, _| ui::ContextMenuStory.render()) }.into_any() - } - Self::Facepile => { - { cx.build_view(|cx| (), |_, _| ui::FacepileStory.render()) }.into_any() - } - Self::Keybinding => { - { cx.build_view(|cx| (), |_, _| ui::KeybindingStory.render()) }.into_any() - } - Self::LanguageSelector => { - { cx.build_view(|cx| (), |_, _| ui::LanguageSelectorStory.render()) }.into_any() - } - Self::MultiBuffer => { - { cx.build_view(|cx| (), |_, _| ui::MultiBufferStory.render()) }.into_any() - } - Self::NotificationsPanel => { - { cx.build_view(|cx| (), |_, _| ui::NotificationsPanelStory.render()) }.into_any() - } - Self::Palette => { - { cx.build_view(|cx| (), |_, _| ui::PaletteStory.render()) }.into_any() - } - Self::Panel => { cx.build_view(|cx| (), |_, _| ui::PanelStory.render()) }.into_any(), - Self::ProjectPanel => { - { cx.build_view(|cx| (), |_, _| ui::ProjectPanelStory.render()) }.into_any() - } - Self::RecentProjects => { - { cx.build_view(|cx| (), |_, _| ui::RecentProjectsStory.render()) }.into_any() - } - Self::Tab => { cx.build_view(|cx| (), |_, _| ui::TabStory.render()) }.into_any(), - Self::TabBar => { cx.build_view(|cx| (), |_, _| ui::TabBarStory.render()) }.into_any(), - Self::Terminal => { - { cx.build_view(|cx| (), |_, _| ui::TerminalStory.render()) }.into_any() - } - Self::ThemeSelector => { - { cx.build_view(|cx| (), |_, _| ui::ThemeSelectorStory.render()) }.into_any() - } + Self::AssistantPanel => cx.build_view(|_| ui::AssistantPanelStory).into_any(), + Self::Buffer => cx.build_view(|_| ui::BufferStory).into_any(), + Self::Breadcrumb => cx.build_view(|_| ui::BreadcrumbStory).into_any(), + Self::ChatPanel => cx.build_view(|_| ui::ChatPanelStory).into_any(), + Self::CollabPanel => cx.build_view(|_| ui::CollabPanelStory).into_any(), + Self::CommandPalette => cx.build_view(|_| ui::CommandPaletteStory).into_any(), + Self::ContextMenu => cx.build_view(|_| ui::ContextMenuStory).into_any(), + Self::Facepile => cx.build_view(|_| ui::FacepileStory).into_any(), + Self::Keybinding => cx.build_view(|_| ui::KeybindingStory).into_any(), + Self::LanguageSelector => cx.build_view(|_| ui::LanguageSelectorStory).into_any(), + Self::MultiBuffer => cx.build_view(|_| ui::MultiBufferStory).into_any(), + Self::NotificationsPanel => cx.build_view(|cx| ui::NotificationsPanelStory).into_any(), + Self::Palette => cx.build_view(|cx| ui::PaletteStory).into_any(), + Self::Panel => cx.build_view(|cx| ui::PanelStory).into_any(), + Self::ProjectPanel => cx.build_view(|_| ui::ProjectPanelStory).into_any(), + Self::RecentProjects => cx.build_view(|_| ui::RecentProjectsStory).into_any(), + Self::Tab => cx.build_view(|_| ui::TabStory).into_any(), + Self::TabBar => cx.build_view(|_| ui::TabBarStory).into_any(), + Self::Terminal => cx.build_view(|_| ui::TerminalStory).into_any(), + Self::ThemeSelector => cx.build_view(|_| ui::ThemeSelectorStory).into_any(), + Self::Toast => cx.build_view(|_| ui::ToastStory).into_any(), + Self::Toolbar => cx.build_view(|_| ui::ToolbarStory).into_any(), + Self::TrafficLights => cx.build_view(|_| ui::TrafficLightsStory).into_any(), + Self::Copilot => cx.build_view(|_| ui::CopilotModalStory).into_any(), Self::TitleBar => ui::TitleBarStory::view(cx).into_any(), - Self::Toast => { cx.build_view(|cx| (), |_, _| ui::ToastStory.render()) }.into_any(), - Self::Toolbar => { - { cx.build_view(|cx| (), |_, _| ui::ToolbarStory.render()) }.into_any() - } - Self::TrafficLights => { - { cx.build_view(|cx| (), |_, _| ui::TrafficLightsStory.render()) }.into_any() - } - Self::Copilot => { - { cx.build_view(|cx| (), |_, _| ui::CopilotModalStory.render()) }.into_any() - } Self::Workspace => ui::WorkspaceStory::view(cx).into_any(), } } diff --git a/crates/storybook2/src/storybook2.rs b/crates/storybook2/src/storybook2.rs index a06a1392b2..c2903c88e1 100644 --- a/crates/storybook2/src/storybook2.rs +++ b/crates/storybook2/src/storybook2.rs @@ -4,21 +4,20 @@ mod assets; mod stories; mod story; mod story_selector; -mod themes; use std::sync::Arc; use clap::Parser; use gpui2::{ - div, px, size, AnyView, AppContext, Bounds, ViewContext, VisualContext, WindowBounds, - WindowOptions, + div, px, size, AnyView, AppContext, Bounds, Div, Render, ViewContext, VisualContext, + WindowBounds, WindowOptions, }; use log::LevelFilter; use settings2::{default_settings, Settings, SettingsStore}; use simplelog::SimpleLogger; use story_selector::ComponentStory; use theme2::{ThemeRegistry, ThemeSettings}; -use ui::{prelude::*, themed}; +use ui::prelude::*; use crate::assets::Assets; use crate::story_selector::StorySelector; @@ -50,7 +49,6 @@ fn main() { let story_selector = args.story.clone(); let theme_name = args.theme.unwrap_or("One Dark".to_string()); - let theme = themes::load_theme(theme_name.clone()).unwrap(); let asset_source = Arc::new(Assets); gpui2::App::production(asset_source).run(move |cx| { @@ -84,12 +82,7 @@ fn main() { }), ..Default::default() }, - move |cx| { - cx.build_view( - |cx| StoryWrapper::new(selector.story(cx), theme), - StoryWrapper::render, - ) - }, + move |cx| cx.build_view(|cx| StoryWrapper::new(selector.story(cx))), ); cx.activate(true); @@ -99,22 +92,23 @@ fn main() { #[derive(Clone)] pub struct StoryWrapper { story: AnyView, - theme: Theme, } impl StoryWrapper { - pub(crate) fn new(story: AnyView, theme: Theme) -> Self { - Self { story, theme } + pub(crate) fn new(story: AnyView) -> Self { + Self { story } } +} - fn render(&mut self, cx: &mut ViewContext) -> impl Component { - themed(self.theme.clone(), cx, |cx| { - div() - .flex() - .flex_col() - .size_full() - .child(self.story.clone()) - }) +impl Render for StoryWrapper { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Self::Element { + div() + .flex() + .flex_col() + .size_full() + .child(self.story.clone()) } } diff --git a/crates/storybook2/src/themes.rs b/crates/storybook2/src/themes.rs deleted file mode 100644 index ade7cbea87..0000000000 --- a/crates/storybook2/src/themes.rs +++ /dev/null @@ -1,30 +0,0 @@ -mod rose_pine; - -pub use rose_pine::*; - -use anyhow::{Context, Result}; -use gpui2::serde_json; -use serde::Deserialize; -use ui::Theme; - -use crate::assets::Assets; - -#[derive(Deserialize)] -struct LegacyTheme { - pub base_theme: serde_json::Value, -} - -/// Loads the [`Theme`] with the given name. -pub fn load_theme(name: String) -> Result { - let theme_contents = Assets::get(&format!("themes/{name}.json")) - .with_context(|| format!("theme file not found: '{name}'"))?; - - let legacy_theme: LegacyTheme = - serde_json::from_str(std::str::from_utf8(&theme_contents.data)?) - .context("failed to parse legacy theme")?; - - let theme: Theme = serde_json::from_value(legacy_theme.base_theme.clone()) - .context("failed to parse `base_theme`")?; - - Ok(theme) -} diff --git a/crates/storybook2/src/themes/rose_pine.rs b/crates/storybook2/src/themes/rose_pine.rs deleted file mode 100644 index a553f87d77..0000000000 --- a/crates/storybook2/src/themes/rose_pine.rs +++ /dev/null @@ -1,1686 +0,0 @@ -use gpui2::serde_json::{self, json}; -use ui::Theme; - -pub fn rose_pine() -> Theme { - serde_json::from_value(json! { - { - "name": "Rosé Pine", - "is_light": false, - "ramps": {}, - "lowest": { - "base": { - "default": { - "background": "#292739", - "border": "#423f55", - "foreground": "#e0def4" - }, - "hovered": { - "background": "#423f55", - "border": "#423f55", - "foreground": "#e0def4" - }, - "pressed": { - "background": "#4e4b63", - "border": "#423f55", - "foreground": "#e0def4" - }, - "active": { - "background": "#47445b", - "border": "#36334a", - "foreground": "#e0def4" - }, - "disabled": { - "background": "#292739", - "border": "#353347", - "foreground": "#2f2b43" - }, - "inverted": { - "background": "#e0def4", - "border": "#191724", - "foreground": "#4b4860" - } - }, - "variant": { - "default": { - "background": "#292739", - "border": "#423f55", - "foreground": "#75718e" - }, - "hovered": { - "background": "#423f55", - "border": "#423f55", - "foreground": "#75718e" - }, - "pressed": { - "background": "#4e4b63", - "border": "#423f55", - "foreground": "#75718e" - }, - "active": { - "background": "#47445b", - "border": "#36334a", - "foreground": "#e0def4" - }, - "disabled": { - "background": "#292739", - "border": "#353347", - "foreground": "#2f2b43" - }, - "inverted": { - "background": "#e0def4", - "border": "#191724", - "foreground": "#4b4860" - } - }, - "on": { - "default": { - "background": "#1d1b2a", - "border": "#232132", - "foreground": "#e0def4" - }, - "hovered": { - "background": "#232132", - "border": "#232132", - "foreground": "#e0def4" - }, - "pressed": { - "background": "#2f2d40", - "border": "#232132", - "foreground": "#e0def4" - }, - "active": { - "background": "#403e53", - "border": "#504d65", - "foreground": "#e0def4" - }, - "disabled": { - "background": "#1d1b2a", - "border": "#1e1c2c", - "foreground": "#3b384f" - }, - "inverted": { - "background": "#e0def4", - "border": "#191724", - "foreground": "#3b394e" - } - }, - "accent": { - "default": { - "background": "#2f3739", - "border": "#435255", - "foreground": "#9cced7" - }, - "hovered": { - "background": "#435255", - "border": "#435255", - "foreground": "#9cced7" - }, - "pressed": { - "background": "#4e6164", - "border": "#435255", - "foreground": "#9cced7" - }, - "active": { - "background": "#5d757a", - "border": "#6e8f94", - "foreground": "#fbfdfd" - }, - "disabled": { - "background": "#2f3739", - "border": "#3a4446", - "foreground": "#85aeb5" - }, - "inverted": { - "background": "#fbfdfd", - "border": "#171717", - "foreground": "#587074" - } - }, - "positive": { - "default": { - "background": "#182e23", - "border": "#254839", - "foreground": "#5dc2a3" - }, - "hovered": { - "background": "#254839", - "border": "#254839", - "foreground": "#5dc2a3" - }, - "pressed": { - "background": "#2c5645", - "border": "#254839", - "foreground": "#5dc2a3" - }, - "active": { - "background": "#356b57", - "border": "#40836c", - "foreground": "#f9fdfb" - }, - "disabled": { - "background": "#182e23", - "border": "#1e3b2e", - "foreground": "#4ea287" - }, - "inverted": { - "background": "#f9fdfb", - "border": "#000e00", - "foreground": "#326552" - } - }, - "warning": { - "default": { - "background": "#50341a", - "border": "#6d4d2b", - "foreground": "#f5c177" - }, - "hovered": { - "background": "#6d4d2b", - "border": "#6d4d2b", - "foreground": "#f5c177" - }, - "pressed": { - "background": "#7e5a34", - "border": "#6d4d2b", - "foreground": "#f5c177" - }, - "active": { - "background": "#946e41", - "border": "#b0854f", - "foreground": "#fffcf9" - }, - "disabled": { - "background": "#50341a", - "border": "#5e4023", - "foreground": "#d2a263" - }, - "inverted": { - "background": "#fffcf9", - "border": "#2c1600", - "foreground": "#8e683c" - } - }, - "negative": { - "default": { - "background": "#431820", - "border": "#612834", - "foreground": "#ea6f92" - }, - "hovered": { - "background": "#612834", - "border": "#612834", - "foreground": "#ea6f92" - }, - "pressed": { - "background": "#71303f", - "border": "#612834", - "foreground": "#ea6f92" - }, - "active": { - "background": "#883c4f", - "border": "#a44961", - "foreground": "#fff9fa" - }, - "disabled": { - "background": "#431820", - "border": "#52202a", - "foreground": "#c75c79" - }, - "inverted": { - "background": "#fff9fa", - "border": "#230000", - "foreground": "#82384a" - } - } - }, - "middle": { - "base": { - "default": { - "background": "#1d1b2a", - "border": "#232132", - "foreground": "#e0def4" - }, - "hovered": { - "background": "#232132", - "border": "#232132", - "foreground": "#e0def4" - }, - "pressed": { - "background": "#2f2d40", - "border": "#232132", - "foreground": "#e0def4" - }, - "active": { - "background": "#403e53", - "border": "#504d65", - "foreground": "#e0def4" - }, - "disabled": { - "background": "#1d1b2a", - "border": "#1e1c2c", - "foreground": "#3b384f" - }, - "inverted": { - "background": "#e0def4", - "border": "#191724", - "foreground": "#3b394e" - } - }, - "variant": { - "default": { - "background": "#1d1b2a", - "border": "#232132", - "foreground": "#75718e" - }, - "hovered": { - "background": "#232132", - "border": "#232132", - "foreground": "#75718e" - }, - "pressed": { - "background": "#2f2d40", - "border": "#232132", - "foreground": "#75718e" - }, - "active": { - "background": "#403e53", - "border": "#504d65", - "foreground": "#e0def4" - }, - "disabled": { - "background": "#1d1b2a", - "border": "#1e1c2c", - "foreground": "#3b384f" - }, - "inverted": { - "background": "#e0def4", - "border": "#191724", - "foreground": "#3b394e" - } - }, - "on": { - "default": { - "background": "#191724", - "border": "#1c1a29", - "foreground": "#e0def4" - }, - "hovered": { - "background": "#1c1a29", - "border": "#1c1a29", - "foreground": "#e0def4" - }, - "pressed": { - "background": "#1d1b2b", - "border": "#1c1a29", - "foreground": "#e0def4" - }, - "active": { - "background": "#222031", - "border": "#353347", - "foreground": "#e0def4" - }, - "disabled": { - "background": "#191724", - "border": "#1a1826", - "foreground": "#4e4b63" - }, - "inverted": { - "background": "#e0def4", - "border": "#191724", - "foreground": "#1f1d2e" - } - }, - "accent": { - "default": { - "background": "#2f3739", - "border": "#435255", - "foreground": "#9cced7" - }, - "hovered": { - "background": "#435255", - "border": "#435255", - "foreground": "#9cced7" - }, - "pressed": { - "background": "#4e6164", - "border": "#435255", - "foreground": "#9cced7" - }, - "active": { - "background": "#5d757a", - "border": "#6e8f94", - "foreground": "#fbfdfd" - }, - "disabled": { - "background": "#2f3739", - "border": "#3a4446", - "foreground": "#85aeb5" - }, - "inverted": { - "background": "#fbfdfd", - "border": "#171717", - "foreground": "#587074" - } - }, - "positive": { - "default": { - "background": "#182e23", - "border": "#254839", - "foreground": "#5dc2a3" - }, - "hovered": { - "background": "#254839", - "border": "#254839", - "foreground": "#5dc2a3" - }, - "pressed": { - "background": "#2c5645", - "border": "#254839", - "foreground": "#5dc2a3" - }, - "active": { - "background": "#356b57", - "border": "#40836c", - "foreground": "#f9fdfb" - }, - "disabled": { - "background": "#182e23", - "border": "#1e3b2e", - "foreground": "#4ea287" - }, - "inverted": { - "background": "#f9fdfb", - "border": "#000e00", - "foreground": "#326552" - } - }, - "warning": { - "default": { - "background": "#50341a", - "border": "#6d4d2b", - "foreground": "#f5c177" - }, - "hovered": { - "background": "#6d4d2b", - "border": "#6d4d2b", - "foreground": "#f5c177" - }, - "pressed": { - "background": "#7e5a34", - "border": "#6d4d2b", - "foreground": "#f5c177" - }, - "active": { - "background": "#946e41", - "border": "#b0854f", - "foreground": "#fffcf9" - }, - "disabled": { - "background": "#50341a", - "border": "#5e4023", - "foreground": "#d2a263" - }, - "inverted": { - "background": "#fffcf9", - "border": "#2c1600", - "foreground": "#8e683c" - } - }, - "negative": { - "default": { - "background": "#431820", - "border": "#612834", - "foreground": "#ea6f92" - }, - "hovered": { - "background": "#612834", - "border": "#612834", - "foreground": "#ea6f92" - }, - "pressed": { - "background": "#71303f", - "border": "#612834", - "foreground": "#ea6f92" - }, - "active": { - "background": "#883c4f", - "border": "#a44961", - "foreground": "#fff9fa" - }, - "disabled": { - "background": "#431820", - "border": "#52202a", - "foreground": "#c75c79" - }, - "inverted": { - "background": "#fff9fa", - "border": "#230000", - "foreground": "#82384a" - } - } - }, - "highest": { - "base": { - "default": { - "background": "#191724", - "border": "#1c1a29", - "foreground": "#e0def4" - }, - "hovered": { - "background": "#1c1a29", - "border": "#1c1a29", - "foreground": "#e0def4" - }, - "pressed": { - "background": "#1d1b2b", - "border": "#1c1a29", - "foreground": "#e0def4" - }, - "active": { - "background": "#222031", - "border": "#353347", - "foreground": "#e0def4" - }, - "disabled": { - "background": "#191724", - "border": "#1a1826", - "foreground": "#4e4b63" - }, - "inverted": { - "background": "#e0def4", - "border": "#191724", - "foreground": "#1f1d2e" - } - }, - "variant": { - "default": { - "background": "#191724", - "border": "#1c1a29", - "foreground": "#75718e" - }, - "hovered": { - "background": "#1c1a29", - "border": "#1c1a29", - "foreground": "#75718e" - }, - "pressed": { - "background": "#1d1b2b", - "border": "#1c1a29", - "foreground": "#75718e" - }, - "active": { - "background": "#222031", - "border": "#353347", - "foreground": "#e0def4" - }, - "disabled": { - "background": "#191724", - "border": "#1a1826", - "foreground": "#4e4b63" - }, - "inverted": { - "background": "#e0def4", - "border": "#191724", - "foreground": "#1f1d2e" - } - }, - "on": { - "default": { - "background": "#1d1b2a", - "border": "#232132", - "foreground": "#e0def4" - }, - "hovered": { - "background": "#232132", - "border": "#232132", - "foreground": "#e0def4" - }, - "pressed": { - "background": "#2f2d40", - "border": "#232132", - "foreground": "#e0def4" - }, - "active": { - "background": "#403e53", - "border": "#504d65", - "foreground": "#e0def4" - }, - "disabled": { - "background": "#1d1b2a", - "border": "#1e1c2c", - "foreground": "#3b384f" - }, - "inverted": { - "background": "#e0def4", - "border": "#191724", - "foreground": "#3b394e" - } - }, - "accent": { - "default": { - "background": "#2f3739", - "border": "#435255", - "foreground": "#9cced7" - }, - "hovered": { - "background": "#435255", - "border": "#435255", - "foreground": "#9cced7" - }, - "pressed": { - "background": "#4e6164", - "border": "#435255", - "foreground": "#9cced7" - }, - "active": { - "background": "#5d757a", - "border": "#6e8f94", - "foreground": "#fbfdfd" - }, - "disabled": { - "background": "#2f3739", - "border": "#3a4446", - "foreground": "#85aeb5" - }, - "inverted": { - "background": "#fbfdfd", - "border": "#171717", - "foreground": "#587074" - } - }, - "positive": { - "default": { - "background": "#182e23", - "border": "#254839", - "foreground": "#5dc2a3" - }, - "hovered": { - "background": "#254839", - "border": "#254839", - "foreground": "#5dc2a3" - }, - "pressed": { - "background": "#2c5645", - "border": "#254839", - "foreground": "#5dc2a3" - }, - "active": { - "background": "#356b57", - "border": "#40836c", - "foreground": "#f9fdfb" - }, - "disabled": { - "background": "#182e23", - "border": "#1e3b2e", - "foreground": "#4ea287" - }, - "inverted": { - "background": "#f9fdfb", - "border": "#000e00", - "foreground": "#326552" - } - }, - "warning": { - "default": { - "background": "#50341a", - "border": "#6d4d2b", - "foreground": "#f5c177" - }, - "hovered": { - "background": "#6d4d2b", - "border": "#6d4d2b", - "foreground": "#f5c177" - }, - "pressed": { - "background": "#7e5a34", - "border": "#6d4d2b", - "foreground": "#f5c177" - }, - "active": { - "background": "#946e41", - "border": "#b0854f", - "foreground": "#fffcf9" - }, - "disabled": { - "background": "#50341a", - "border": "#5e4023", - "foreground": "#d2a263" - }, - "inverted": { - "background": "#fffcf9", - "border": "#2c1600", - "foreground": "#8e683c" - } - }, - "negative": { - "default": { - "background": "#431820", - "border": "#612834", - "foreground": "#ea6f92" - }, - "hovered": { - "background": "#612834", - "border": "#612834", - "foreground": "#ea6f92" - }, - "pressed": { - "background": "#71303f", - "border": "#612834", - "foreground": "#ea6f92" - }, - "active": { - "background": "#883c4f", - "border": "#a44961", - "foreground": "#fff9fa" - }, - "disabled": { - "background": "#431820", - "border": "#52202a", - "foreground": "#c75c79" - }, - "inverted": { - "background": "#fff9fa", - "border": "#230000", - "foreground": "#82384a" - } - } - }, - "popover_shadow": { - "blur": 4, - "color": "#00000033", - "offset": [ - 1, - 2 - ] - }, - "modal_shadow": { - "blur": 16, - "color": "#00000033", - "offset": [ - 0, - 2 - ] - }, - "players": { - "0": { - "selection": "#9cced73d", - "cursor": "#9cced7" - }, - "1": { - "selection": "#5dc2a33d", - "cursor": "#5dc2a3" - }, - "2": { - "selection": "#9d76913d", - "cursor": "#9d7691" - }, - "3": { - "selection": "#c4a7e63d", - "cursor": "#c4a7e6" - }, - "4": { - "selection": "#c4a7e63d", - "cursor": "#c4a7e6" - }, - "5": { - "selection": "#32748f3d", - "cursor": "#32748f" - }, - "6": { - "selection": "#ea6f923d", - "cursor": "#ea6f92" - }, - "7": { - "selection": "#f5c1773d", - "cursor": "#f5c177" - } - }, - "syntax": { - "comment": { - "color": "#6e6a86" - }, - "operator": { - "color": "#31748f" - }, - "punctuation": { - "color": "#908caa" - }, - "variable": { - "color": "#e0def4" - }, - "string": { - "color": "#f6c177" - }, - "type": { - "color": "#9ccfd8" - }, - "type.builtin": { - "color": "#9ccfd8" - }, - "boolean": { - "color": "#ebbcba" - }, - "function": { - "color": "#ebbcba" - }, - "keyword": { - "color": "#31748f" - }, - "tag": { - "color": "#9ccfd8" - }, - "function.method": { - "color": "#ebbcba" - }, - "title": { - "color": "#f6c177" - }, - "link_text": { - "color": "#9ccfd8", - "italic": false - }, - "link_uri": { - "color": "#ebbcba" - } - }, - "color_family": { - "neutral": { - "low": 11.568627450980392, - "high": 91.37254901960785, - "range": 79.80392156862746, - "scaling_value": 1.2530712530712529 - }, - "red": { - "low": 6.862745098039216, - "high": 100, - "range": 93.13725490196079, - "scaling_value": 1.0736842105263158 - }, - "orange": { - "low": 5.490196078431373, - "high": 100, - "range": 94.50980392156863, - "scaling_value": 1.058091286307054 - }, - "yellow": { - "low": 8.627450980392156, - "high": 100, - "range": 91.37254901960785, - "scaling_value": 1.094420600858369 - }, - "green": { - "low": 2.7450980392156863, - "high": 100, - "range": 97.25490196078431, - "scaling_value": 1.028225806451613 - }, - "cyan": { - "low": 0, - "high": 100, - "range": 100, - "scaling_value": 1 - }, - "blue": { - "low": 9.019607843137255, - "high": 100, - "range": 90.98039215686275, - "scaling_value": 1.0991379310344827 - }, - "violet": { - "low": 5.490196078431373, - "high": 100, - "range": 94.50980392156863, - "scaling_value": 1.058091286307054 - }, - "magenta": { - "low": 0, - "high": 100, - "range": 100, - "scaling_value": 1 - } - } - } - }) - .unwrap() -} - -pub fn rose_pine_dawn() -> Theme { - serde_json::from_value(json!({ - "name": "Rosé Pine Dawn", - "is_light": true, - "ramps": {}, - "lowest": { - "base": { - "default": { - "background": "#dcd8d8", - "border": "#dcd6d5", - "foreground": "#575279" - }, - "hovered": { - "background": "#dcd6d5", - "border": "#dcd6d5", - "foreground": "#575279" - }, - "pressed": { - "background": "#efe6df", - "border": "#dcd6d5", - "foreground": "#575279" - }, - "active": { - "background": "#c1bac1", - "border": "#a9a3b0", - "foreground": "#575279" - }, - "disabled": { - "background": "#dcd8d8", - "border": "#d0cccf", - "foreground": "#938fa3" - }, - "inverted": { - "background": "#575279", - "border": "#faf4ed", - "foreground": "#c7c0c5" - } - }, - "variant": { - "default": { - "background": "#dcd8d8", - "border": "#dcd6d5", - "foreground": "#706c8c" - }, - "hovered": { - "background": "#dcd6d5", - "border": "#dcd6d5", - "foreground": "#706c8c" - }, - "pressed": { - "background": "#efe6df", - "border": "#dcd6d5", - "foreground": "#706c8c" - }, - "active": { - "background": "#c1bac1", - "border": "#a9a3b0", - "foreground": "#575279" - }, - "disabled": { - "background": "#dcd8d8", - "border": "#d0cccf", - "foreground": "#938fa3" - }, - "inverted": { - "background": "#575279", - "border": "#faf4ed", - "foreground": "#c7c0c5" - } - }, - "on": { - "default": { - "background": "#fef9f2", - "border": "#e5e0df", - "foreground": "#575279" - }, - "hovered": { - "background": "#e5e0df", - "border": "#e5e0df", - "foreground": "#575279" - }, - "pressed": { - "background": "#d4d0d2", - "border": "#e5e0df", - "foreground": "#575279" - }, - "active": { - "background": "#dbd5d4", - "border": "#dbd3d1", - "foreground": "#575279" - }, - "disabled": { - "background": "#fef9f2", - "border": "#f6f1eb", - "foreground": "#b1abb5" - }, - "inverted": { - "background": "#575279", - "border": "#faf4ed", - "foreground": "#d6d1d1" - } - }, - "accent": { - "default": { - "background": "#dde9eb", - "border": "#c3d7db", - "foreground": "#57949f" - }, - "hovered": { - "background": "#c3d7db", - "border": "#c3d7db", - "foreground": "#57949f" - }, - "pressed": { - "background": "#b6cfd3", - "border": "#c3d7db", - "foreground": "#57949f" - }, - "active": { - "background": "#a3c3c9", - "border": "#8db6bd", - "foreground": "#06090a" - }, - "disabled": { - "background": "#dde9eb", - "border": "#d0e0e3", - "foreground": "#72a5ae" - }, - "inverted": { - "background": "#06090a", - "border": "#ffffff", - "foreground": "#a8c7cd" - } - }, - "positive": { - "default": { - "background": "#dbeee7", - "border": "#bee0d5", - "foreground": "#3eaa8e" - }, - "hovered": { - "background": "#bee0d5", - "border": "#bee0d5", - "foreground": "#3eaa8e" - }, - "pressed": { - "background": "#b0dacb", - "border": "#bee0d5", - "foreground": "#3eaa8e" - }, - "active": { - "background": "#9bd0bf", - "border": "#82c6b1", - "foreground": "#060a09" - }, - "disabled": { - "background": "#dbeee7", - "border": "#cde7de", - "foreground": "#63b89f" - }, - "inverted": { - "background": "#060a09", - "border": "#ffffff", - "foreground": "#a1d4c3" - } - }, - "warning": { - "default": { - "background": "#ffebd6", - "border": "#ffdab7", - "foreground": "#e99d35" - }, - "hovered": { - "background": "#ffdab7", - "border": "#ffdab7", - "foreground": "#e99d35" - }, - "pressed": { - "background": "#fed2a6", - "border": "#ffdab7", - "foreground": "#e99d35" - }, - "active": { - "background": "#fbc891", - "border": "#f7bc77", - "foreground": "#330704" - }, - "disabled": { - "background": "#ffebd6", - "border": "#ffe2c7", - "foreground": "#f1ac57" - }, - "inverted": { - "background": "#330704", - "border": "#ffffff", - "foreground": "#fccb97" - } - }, - "negative": { - "default": { - "background": "#f1dfe3", - "border": "#e6c6cd", - "foreground": "#b4647a" - }, - "hovered": { - "background": "#e6c6cd", - "border": "#e6c6cd", - "foreground": "#b4647a" - }, - "pressed": { - "background": "#e0bac2", - "border": "#e6c6cd", - "foreground": "#b4647a" - }, - "active": { - "background": "#d8a8b3", - "border": "#ce94a3", - "foreground": "#0b0708" - }, - "disabled": { - "background": "#f1dfe3", - "border": "#ecd2d8", - "foreground": "#c17b8e" - }, - "inverted": { - "background": "#0b0708", - "border": "#ffffff", - "foreground": "#dbadb8" - } - } - }, - "middle": { - "base": { - "default": { - "background": "#fef9f2", - "border": "#e5e0df", - "foreground": "#575279" - }, - "hovered": { - "background": "#e5e0df", - "border": "#e5e0df", - "foreground": "#575279" - }, - "pressed": { - "background": "#d4d0d2", - "border": "#e5e0df", - "foreground": "#575279" - }, - "active": { - "background": "#dbd5d4", - "border": "#dbd3d1", - "foreground": "#575279" - }, - "disabled": { - "background": "#fef9f2", - "border": "#f6f1eb", - "foreground": "#b1abb5" - }, - "inverted": { - "background": "#575279", - "border": "#faf4ed", - "foreground": "#d6d1d1" - } - }, - "variant": { - "default": { - "background": "#fef9f2", - "border": "#e5e0df", - "foreground": "#706c8c" - }, - "hovered": { - "background": "#e5e0df", - "border": "#e5e0df", - "foreground": "#706c8c" - }, - "pressed": { - "background": "#d4d0d2", - "border": "#e5e0df", - "foreground": "#706c8c" - }, - "active": { - "background": "#dbd5d4", - "border": "#dbd3d1", - "foreground": "#575279" - }, - "disabled": { - "background": "#fef9f2", - "border": "#f6f1eb", - "foreground": "#b1abb5" - }, - "inverted": { - "background": "#575279", - "border": "#faf4ed", - "foreground": "#d6d1d1" - } - }, - "on": { - "default": { - "background": "#faf4ed", - "border": "#fdf8f1", - "foreground": "#575279" - }, - "hovered": { - "background": "#fdf8f1", - "border": "#fdf8f1", - "foreground": "#575279" - }, - "pressed": { - "background": "#fdf8f2", - "border": "#fdf8f1", - "foreground": "#575279" - }, - "active": { - "background": "#e6e1e0", - "border": "#d0cccf", - "foreground": "#575279" - }, - "disabled": { - "background": "#faf4ed", - "border": "#fcf6ef", - "foreground": "#efe6df" - }, - "inverted": { - "background": "#575279", - "border": "#faf4ed", - "foreground": "#ede9e5" - } - }, - "accent": { - "default": { - "background": "#dde9eb", - "border": "#c3d7db", - "foreground": "#57949f" - }, - "hovered": { - "background": "#c3d7db", - "border": "#c3d7db", - "foreground": "#57949f" - }, - "pressed": { - "background": "#b6cfd3", - "border": "#c3d7db", - "foreground": "#57949f" - }, - "active": { - "background": "#a3c3c9", - "border": "#8db6bd", - "foreground": "#06090a" - }, - "disabled": { - "background": "#dde9eb", - "border": "#d0e0e3", - "foreground": "#72a5ae" - }, - "inverted": { - "background": "#06090a", - "border": "#ffffff", - "foreground": "#a8c7cd" - } - }, - "positive": { - "default": { - "background": "#dbeee7", - "border": "#bee0d5", - "foreground": "#3eaa8e" - }, - "hovered": { - "background": "#bee0d5", - "border": "#bee0d5", - "foreground": "#3eaa8e" - }, - "pressed": { - "background": "#b0dacb", - "border": "#bee0d5", - "foreground": "#3eaa8e" - }, - "active": { - "background": "#9bd0bf", - "border": "#82c6b1", - "foreground": "#060a09" - }, - "disabled": { - "background": "#dbeee7", - "border": "#cde7de", - "foreground": "#63b89f" - }, - "inverted": { - "background": "#060a09", - "border": "#ffffff", - "foreground": "#a1d4c3" - } - }, - "warning": { - "default": { - "background": "#ffebd6", - "border": "#ffdab7", - "foreground": "#e99d35" - }, - "hovered": { - "background": "#ffdab7", - "border": "#ffdab7", - "foreground": "#e99d35" - }, - "pressed": { - "background": "#fed2a6", - "border": "#ffdab7", - "foreground": "#e99d35" - }, - "active": { - "background": "#fbc891", - "border": "#f7bc77", - "foreground": "#330704" - }, - "disabled": { - "background": "#ffebd6", - "border": "#ffe2c7", - "foreground": "#f1ac57" - }, - "inverted": { - "background": "#330704", - "border": "#ffffff", - "foreground": "#fccb97" - } - }, - "negative": { - "default": { - "background": "#f1dfe3", - "border": "#e6c6cd", - "foreground": "#b4647a" - }, - "hovered": { - "background": "#e6c6cd", - "border": "#e6c6cd", - "foreground": "#b4647a" - }, - "pressed": { - "background": "#e0bac2", - "border": "#e6c6cd", - "foreground": "#b4647a" - }, - "active": { - "background": "#d8a8b3", - "border": "#ce94a3", - "foreground": "#0b0708" - }, - "disabled": { - "background": "#f1dfe3", - "border": "#ecd2d8", - "foreground": "#c17b8e" - }, - "inverted": { - "background": "#0b0708", - "border": "#ffffff", - "foreground": "#dbadb8" - } - } - }, - "highest": { - "base": { - "default": { - "background": "#faf4ed", - "border": "#fdf8f1", - "foreground": "#575279" - }, - "hovered": { - "background": "#fdf8f1", - "border": "#fdf8f1", - "foreground": "#575279" - }, - "pressed": { - "background": "#fdf8f2", - "border": "#fdf8f1", - "foreground": "#575279" - }, - "active": { - "background": "#e6e1e0", - "border": "#d0cccf", - "foreground": "#575279" - }, - "disabled": { - "background": "#faf4ed", - "border": "#fcf6ef", - "foreground": "#efe6df" - }, - "inverted": { - "background": "#575279", - "border": "#faf4ed", - "foreground": "#ede9e5" - } - }, - "variant": { - "default": { - "background": "#faf4ed", - "border": "#fdf8f1", - "foreground": "#706c8c" - }, - "hovered": { - "background": "#fdf8f1", - "border": "#fdf8f1", - "foreground": "#706c8c" - }, - "pressed": { - "background": "#fdf8f2", - "border": "#fdf8f1", - "foreground": "#706c8c" - }, - "active": { - "background": "#e6e1e0", - "border": "#d0cccf", - "foreground": "#575279" - }, - "disabled": { - "background": "#faf4ed", - "border": "#fcf6ef", - "foreground": "#efe6df" - }, - "inverted": { - "background": "#575279", - "border": "#faf4ed", - "foreground": "#ede9e5" - } - }, - "on": { - "default": { - "background": "#fef9f2", - "border": "#e5e0df", - "foreground": "#575279" - }, - "hovered": { - "background": "#e5e0df", - "border": "#e5e0df", - "foreground": "#575279" - }, - "pressed": { - "background": "#d4d0d2", - "border": "#e5e0df", - "foreground": "#575279" - }, - "active": { - "background": "#dbd5d4", - "border": "#dbd3d1", - "foreground": "#575279" - }, - "disabled": { - "background": "#fef9f2", - "border": "#f6f1eb", - "foreground": "#b1abb5" - }, - "inverted": { - "background": "#575279", - "border": "#faf4ed", - "foreground": "#d6d1d1" - } - }, - "accent": { - "default": { - "background": "#dde9eb", - "border": "#c3d7db", - "foreground": "#57949f" - }, - "hovered": { - "background": "#c3d7db", - "border": "#c3d7db", - "foreground": "#57949f" - }, - "pressed": { - "background": "#b6cfd3", - "border": "#c3d7db", - "foreground": "#57949f" - }, - "active": { - "background": "#a3c3c9", - "border": "#8db6bd", - "foreground": "#06090a" - }, - "disabled": { - "background": "#dde9eb", - "border": "#d0e0e3", - "foreground": "#72a5ae" - }, - "inverted": { - "background": "#06090a", - "border": "#ffffff", - "foreground": "#a8c7cd" - } - }, - "positive": { - "default": { - "background": "#dbeee7", - "border": "#bee0d5", - "foreground": "#3eaa8e" - }, - "hovered": { - "background": "#bee0d5", - "border": "#bee0d5", - "foreground": "#3eaa8e" - }, - "pressed": { - "background": "#b0dacb", - "border": "#bee0d5", - "foreground": "#3eaa8e" - }, - "active": { - "background": "#9bd0bf", - "border": "#82c6b1", - "foreground": "#060a09" - }, - "disabled": { - "background": "#dbeee7", - "border": "#cde7de", - "foreground": "#63b89f" - }, - "inverted": { - "background": "#060a09", - "border": "#ffffff", - "foreground": "#a1d4c3" - } - }, - "warning": { - "default": { - "background": "#ffebd6", - "border": "#ffdab7", - "foreground": "#e99d35" - }, - "hovered": { - "background": "#ffdab7", - "border": "#ffdab7", - "foreground": "#e99d35" - }, - "pressed": { - "background": "#fed2a6", - "border": "#ffdab7", - "foreground": "#e99d35" - }, - "active": { - "background": "#fbc891", - "border": "#f7bc77", - "foreground": "#330704" - }, - "disabled": { - "background": "#ffebd6", - "border": "#ffe2c7", - "foreground": "#f1ac57" - }, - "inverted": { - "background": "#330704", - "border": "#ffffff", - "foreground": "#fccb97" - } - }, - "negative": { - "default": { - "background": "#f1dfe3", - "border": "#e6c6cd", - "foreground": "#b4647a" - }, - "hovered": { - "background": "#e6c6cd", - "border": "#e6c6cd", - "foreground": "#b4647a" - }, - "pressed": { - "background": "#e0bac2", - "border": "#e6c6cd", - "foreground": "#b4647a" - }, - "active": { - "background": "#d8a8b3", - "border": "#ce94a3", - "foreground": "#0b0708" - }, - "disabled": { - "background": "#f1dfe3", - "border": "#ecd2d8", - "foreground": "#c17b8e" - }, - "inverted": { - "background": "#0b0708", - "border": "#ffffff", - "foreground": "#dbadb8" - } - } - }, - "popover_shadow": { - "blur": 4, - "color": "#2c2a4d33", - "offset": [ - 1, - 2 - ] - }, - "modal_shadow": { - "blur": 16, - "color": "#2c2a4d33", - "offset": [ - 0, - 2 - ] - }, - "players": { - "0": { - "selection": "#57949f3d", - "cursor": "#57949f" - }, - "1": { - "selection": "#3eaa8e3d", - "cursor": "#3eaa8e" - }, - "2": { - "selection": "#7c697f3d", - "cursor": "#7c697f" - }, - "3": { - "selection": "#907aa93d", - "cursor": "#907aa9" - }, - "4": { - "selection": "#907aa93d", - "cursor": "#907aa9" - }, - "5": { - "selection": "#2a69833d", - "cursor": "#2a6983" - }, - "6": { - "selection": "#b4647a3d", - "cursor": "#b4647a" - }, - "7": { - "selection": "#e99d353d", - "cursor": "#e99d35" - } - }, - "syntax": { - "comment": { - "color": "#9893a5" - }, - "operator": { - "color": "#286983" - }, - "punctuation": { - "color": "#797593" - }, - "variable": { - "color": "#575279" - }, - "string": { - "color": "#ea9d34" - }, - "type": { - "color": "#56949f" - }, - "type.builtin": { - "color": "#56949f" - }, - "boolean": { - "color": "#d7827e" - }, - "function": { - "color": "#d7827e" - }, - "keyword": { - "color": "#286983" - }, - "tag": { - "color": "#56949f" - }, - "function.method": { - "color": "#d7827e" - }, - "title": { - "color": "#ea9d34" - }, - "link_text": { - "color": "#56949f", - "italic": false - }, - "link_uri": { - "color": "#d7827e" - } - }, - "color_family": { - "neutral": { - "low": 39.80392156862745, - "high": 95.49019607843137, - "range": 55.686274509803916, - "scaling_value": 1.7957746478873242 - }, - "red": { - "low": 0, - "high": 100, - "range": 100, - "scaling_value": 1 - }, - "orange": { - "low": 0, - "high": 100, - "range": 100, - "scaling_value": 1 - }, - "yellow": { - "low": 8.823529411764707, - "high": 100, - "range": 91.17647058823529, - "scaling_value": 1.0967741935483872 - }, - "green": { - "low": 0, - "high": 100, - "range": 100, - "scaling_value": 1 - }, - "cyan": { - "low": 0, - "high": 100, - "range": 100, - "scaling_value": 1 - }, - "blue": { - "low": 0, - "high": 100, - "range": 100, - "scaling_value": 1 - }, - "violet": { - "low": 0, - "high": 100, - "range": 100, - "scaling_value": 1 - }, - "magenta": { - "low": 0, - "high": 100, - "range": 100, - "scaling_value": 1 - } - } - })) - .unwrap() -} diff --git a/crates/theme2/src/default.rs b/crates/theme2/src/default.rs new file mode 100644 index 0000000000..41d408f980 --- /dev/null +++ b/crates/theme2/src/default.rs @@ -0,0 +1,2118 @@ +use gpui2::Rgba; +use indexmap::IndexMap; + +use crate::scale::{ColorScaleName, ColorScaleSet, ColorScales}; + +struct DefaultColorScaleSet { + scale: ColorScaleName, + light: [&'static str; 12], + light_alpha: [&'static str; 12], + dark: [&'static str; 12], + dark_alpha: [&'static str; 12], +} + +impl From for ColorScaleSet { + fn from(default: DefaultColorScaleSet) -> Self { + Self::new( + default.scale, + default + .light + .map(|color| Rgba::try_from(color).unwrap().into()), + default + .light_alpha + .map(|color| Rgba::try_from(color).unwrap().into()), + default + .dark + .map(|color| Rgba::try_from(color).unwrap().into()), + default + .dark_alpha + .map(|color| Rgba::try_from(color).unwrap().into()), + ) + } +} + +pub fn default_color_scales() -> ColorScales { + use ColorScaleName::*; + + IndexMap::from_iter([ + (Gray, gray().into()), + (Mauve, mauve().into()), + (Slate, slate().into()), + (Sage, sage().into()), + (Olive, olive().into()), + (Sand, sand().into()), + (Gold, gold().into()), + (Bronze, bronze().into()), + (Brown, brown().into()), + (Yellow, yellow().into()), + (Amber, amber().into()), + (Orange, orange().into()), + (Tomato, tomato().into()), + (Red, red().into()), + (Ruby, ruby().into()), + (Crimson, crimson().into()), + (Pink, pink().into()), + (Plum, plum().into()), + (Purple, purple().into()), + (Violet, violet().into()), + (Iris, iris().into()), + (Indigo, indigo().into()), + (Blue, blue().into()), + (Cyan, cyan().into()), + (Teal, teal().into()), + (Jade, jade().into()), + (Green, green().into()), + (Grass, grass().into()), + (Lime, lime().into()), + (Mint, mint().into()), + (Sky, sky().into()), + (Black, black().into()), + (White, white().into()), + ]) +} + +fn gray() -> DefaultColorScaleSet { + DefaultColorScaleSet { + scale: ColorScaleName::Gray, + light: [ + "#fcfcfcff", + "#f9f9f9ff", + "#f0f0f0ff", + "#e8e8e8ff", + "#e0e0e0ff", + "#d9d9d9ff", + "#cececeff", + "#bbbbbbff", + "#8d8d8dff", + "#838383ff", + "#646464ff", + "#202020ff", + ], + light_alpha: [ + "#00000003", + "#00000006", + "#0000000f", + "#00000017", + "#0000001f", + "#00000026", + "#00000031", + "#00000044", + "#00000072", + "#0000007c", + "#0000009b", + "#000000df", + ], + dark: [ + "#111111ff", + "#191919ff", + "#222222ff", + "#2a2a2aff", + "#313131ff", + "#3a3a3aff", + "#484848ff", + "#606060ff", + "#6e6e6eff", + "#7b7b7bff", + "#b4b4b4ff", + "#eeeeeeff", + ], + dark_alpha: [ + "#00000000", + "#ffffff09", + "#ffffff12", + "#ffffff1b", + "#ffffff22", + "#ffffff2c", + "#ffffff3b", + "#ffffff55", + "#ffffff64", + "#ffffff72", + "#ffffffaf", + "#ffffffed", + ], + } +} + +fn mauve() -> DefaultColorScaleSet { + DefaultColorScaleSet { + scale: ColorScaleName::Mauve, + light: [ + "#fdfcfdff", + "#faf9fbff", + "#f2eff3ff", + "#eae7ecff", + "#e3dfe6ff", + "#dbd8e0ff", + "#d0cdd7ff", + "#bcbac7ff", + "#8e8c99ff", + "#84828eff", + "#65636dff", + "#211f26ff", + ], + light_alpha: [ + "#55005503", + "#2b005506", + "#30004010", + "#20003618", + "#20003820", + "#14003527", + "#10003332", + "#08003145", + "#05001d73", + "#0500197d", + "#0400119c", + "#020008e0", + ], + dark: [ + "#121113ff", + "#1a191bff", + "#232225ff", + "#2b292dff", + "#323035ff", + "#3c393fff", + "#49474eff", + "#625f69ff", + "#6f6d78ff", + "#7c7a85ff", + "#b5b2bcff", + "#eeeef0ff", + ], + dark_alpha: [ + "#00000000", + "#f5f4f609", + "#ebeaf814", + "#eee5f81d", + "#efe6fe25", + "#f1e6fd30", + "#eee9ff40", + "#eee7ff5d", + "#eae6fd6e", + "#ece9fd7c", + "#f5f1ffb7", + "#fdfdffef", + ], + } +} + +fn slate() -> DefaultColorScaleSet { + DefaultColorScaleSet { + scale: ColorScaleName::Slate, + light: [ + "#fcfcfdff", + "#f9f9fbff", + "#f0f0f3ff", + "#e8e8ecff", + "#e0e1e6ff", + "#d9d9e0ff", + "#cdced6ff", + "#b9bbc6ff", + "#8b8d98ff", + "#80838dff", + "#60646cff", + "#1c2024ff", + ], + light_alpha: [ + "#00005503", + "#00005506", + "#0000330f", + "#00002d17", + "#0009321f", + "#00002f26", + "#00062e32", + "#00083046", + "#00051d74", + "#00071b7f", + "#0007149f", + "#000509e3", + ], + dark: [ + "#111113ff", + "#18191bff", + "#212225ff", + "#272a2dff", + "#2e3135ff", + "#363a3fff", + "#43484eff", + "#5a6169ff", + "#696e77ff", + "#777b84ff", + "#b0b4baff", + "#edeef0ff", + ], + dark_alpha: [ + "#00000000", + "#d8f4f609", + "#ddeaf814", + "#d3edf81d", + "#d9edfe25", + "#d6ebfd30", + "#d9edff40", + "#d9edff5d", + "#dfebfd6d", + "#e5edfd7b", + "#f1f7feb5", + "#fcfdffef", + ], + } +} + +fn sage() -> DefaultColorScaleSet { + DefaultColorScaleSet { + scale: ColorScaleName::Sage, + light: [ + "#fbfdfcff", + "#f7f9f8ff", + "#eef1f0ff", + "#e6e9e8ff", + "#dfe2e0ff", + "#d7dad9ff", + "#cbcfcdff", + "#b8bcbaff", + "#868e8bff", + "#7c8481ff", + "#5f6563ff", + "#1a211eff", + ], + light_alpha: [ + "#00804004", + "#00402008", + "#002d1e11", + "#001f1519", + "#00180820", + "#00140d28", + "#00140a34", + "#000f0847", + "#00110b79", + "#00100a83", + "#000a07a0", + "#000805e5", + ], + dark: [ + "#101211ff", + "#171918ff", + "#202221ff", + "#272a29ff", + "#2e3130ff", + "#373b39ff", + "#444947ff", + "#5b625fff", + "#63706bff", + "#717d79ff", + "#adb5b2ff", + "#eceeedff", + ], + dark_alpha: [ + "#00000000", + "#f0f2f108", + "#f3f5f412", + "#f2fefd1a", + "#f1fbfa22", + "#edfbf42d", + "#edfcf73c", + "#ebfdf657", + "#dffdf266", + "#e5fdf674", + "#f4fefbb0", + "#fdfffeed", + ], + } +} + +fn olive() -> DefaultColorScaleSet { + DefaultColorScaleSet { + scale: ColorScaleName::Olive, + light: [ + "#fcfdfcff", + "#f8faf8ff", + "#eff1efff", + "#e7e9e7ff", + "#dfe2dfff", + "#d7dad7ff", + "#cccfccff", + "#b9bcb8ff", + "#898e87ff", + "#7f847dff", + "#60655fff", + "#1d211cff", + ], + light_alpha: [ + "#00550003", + "#00490007", + "#00200010", + "#00160018", + "#00180020", + "#00140028", + "#000f0033", + "#040f0047", + "#050f0078", + "#040e0082", + "#020a00a0", + "#010600e3", + ], + dark: [ + "#111210ff", + "#181917ff", + "#212220ff", + "#282a27ff", + "#2f312eff", + "#383a36ff", + "#454843ff", + "#5c625bff", + "#687066ff", + "#767d74ff", + "#afb5adff", + "#eceeecff", + ], + dark_alpha: [ + "#00000000", + "#f1f2f008", + "#f4f5f312", + "#f3fef21a", + "#f2fbf122", + "#f4faed2c", + "#f2fced3b", + "#edfdeb57", + "#ebfde766", + "#f0fdec74", + "#f6fef4b0", + "#fdfffded", + ], + } +} + +fn sand() -> DefaultColorScaleSet { + DefaultColorScaleSet { + scale: ColorScaleName::Sand, + light: [ + "#fdfdfcff", + "#f9f9f8ff", + "#f1f0efff", + "#e9e8e6ff", + "#e2e1deff", + "#dad9d6ff", + "#cfcecaff", + "#bcbbb5ff", + "#8d8d86ff", + "#82827cff", + "#63635eff", + "#21201cff", + ], + light_alpha: [ + "#55550003", + "#25250007", + "#20100010", + "#1f150019", + "#1f180021", + "#19130029", + "#19140035", + "#1915014a", + "#0f0f0079", + "#0c0c0083", + "#080800a1", + "#060500e3", + ], + dark: [ + "#111110ff", + "#191918ff", + "#222221ff", + "#2a2a28ff", + "#31312eff", + "#3b3a37ff", + "#494844ff", + "#62605bff", + "#6f6d66ff", + "#7c7b74ff", + "#b5b3adff", + "#eeeeecff", + ], + dark_alpha: [ + "#00000000", + "#f4f4f309", + "#f6f6f513", + "#fefef31b", + "#fbfbeb23", + "#fffaed2d", + "#fffbed3c", + "#fff9eb57", + "#fffae965", + "#fffdee73", + "#fffcf4b0", + "#fffffded", + ], + } +} + +fn gold() -> DefaultColorScaleSet { + DefaultColorScaleSet { + scale: ColorScaleName::Gold, + light: [ + "#fdfdfcff", + "#faf9f2ff", + "#f2f0e7ff", + "#eae6dbff", + "#e1dccfff", + "#d8d0bfff", + "#cbc0aaff", + "#b9a88dff", + "#978365ff", + "#8c7a5eff", + "#71624bff", + "#3b352bff", + ], + light_alpha: [ + "#55550003", + "#9d8a000d", + "#75600018", + "#6b4e0024", + "#60460030", + "#64440040", + "#63420055", + "#633d0072", + "#5332009a", + "#492d00a1", + "#362100b4", + "#130c00d4", + ], + dark: [ + "#121211ff", + "#1b1a17ff", + "#24231fff", + "#2d2b26ff", + "#38352eff", + "#444039ff", + "#544f46ff", + "#696256ff", + "#978365ff", + "#a39073ff", + "#cbb99fff", + "#e8e2d9ff", + ], + dark_alpha: [ + "#91911102", + "#f9e29d0b", + "#f8ecbb15", + "#ffeec41e", + "#feecc22a", + "#feebcb37", + "#ffedcd48", + "#fdeaca5f", + "#ffdba690", + "#fedfb09d", + "#fee7c6c8", + "#fef7ede7", + ], + } +} + +fn bronze() -> DefaultColorScaleSet { + DefaultColorScaleSet { + scale: ColorScaleName::Bronze, + light: [ + "#fdfcfcff", + "#fdf7f5ff", + "#f6edeaff", + "#efe4dfff", + "#e7d9d3ff", + "#dfcdc5ff", + "#d3bcb3ff", + "#c2a499ff", + "#a18072ff", + "#957468ff", + "#7d5e54ff", + "#43302bff", + ], + light_alpha: [ + "#55000003", + "#cc33000a", + "#92250015", + "#80280020", + "#7423002c", + "#7324003a", + "#6c1f004c", + "#671c0066", + "#551a008d", + "#4c150097", + "#3d0f00ab", + "#1d0600d4", + ], + dark: [ + "#141110ff", + "#1c1917ff", + "#262220ff", + "#302a27ff", + "#3b3330ff", + "#493e3aff", + "#5a4c47ff", + "#6f5f58ff", + "#a18072ff", + "#ae8c7eff", + "#d4b3a5ff", + "#ede0d9ff", + ], + dark_alpha: [ + "#d1110004", + "#fbbc910c", + "#faceb817", + "#facdb622", + "#ffd2c12d", + "#ffd1c03c", + "#fdd0c04f", + "#ffd6c565", + "#fec7b09b", + "#fecab5a9", + "#ffd7c6d1", + "#fff1e9ec", + ], + } +} + +fn brown() -> DefaultColorScaleSet { + DefaultColorScaleSet { + scale: ColorScaleName::Brown, + light: [ + "#fefdfcff", + "#fcf9f6ff", + "#f6eee7ff", + "#f0e4d9ff", + "#ebdacaff", + "#e4cdb7ff", + "#dcbc9fff", + "#cea37eff", + "#ad7f58ff", + "#a07553ff", + "#815e46ff", + "#3e332eff", + ], + light_alpha: [ + "#aa550003", + "#aa550009", + "#a04b0018", + "#9b4a0026", + "#9f4d0035", + "#a04e0048", + "#a34e0060", + "#9f4a0081", + "#823c00a7", + "#723300ac", + "#522100b9", + "#140600d1", + ], + dark: [ + "#12110fff", + "#1c1816ff", + "#28211dff", + "#322922ff", + "#3e3128ff", + "#4d3c2fff", + "#614a39ff", + "#7c5f46ff", + "#ad7f58ff", + "#b88c67ff", + "#dbb594ff", + "#f2e1caff", + ], + dark_alpha: [ + "#91110002", + "#fba67c0c", + "#fcb58c19", + "#fbbb8a24", + "#fcb88931", + "#fdba8741", + "#ffbb8856", + "#ffbe8773", + "#feb87da8", + "#ffc18cb3", + "#fed1aad9", + "#feecd4f2", + ], + } +} + +fn yellow() -> DefaultColorScaleSet { + DefaultColorScaleSet { + scale: ColorScaleName::Yellow, + light: [ + "#fdfdf9ff", + "#fefce9ff", + "#fffab8ff", + "#fff394ff", + "#ffe770ff", + "#f3d768ff", + "#e4c767ff", + "#d5ae39ff", + "#ffe629ff", + "#ffdc00ff", + "#9e6c00ff", + "#473b1fff", + ], + light_alpha: [ + "#aaaa0006", + "#f4dd0016", + "#ffee0047", + "#ffe3016b", + "#ffd5008f", + "#ebbc0097", + "#d2a10098", + "#c99700c6", + "#ffe100d6", + "#ffdc00ff", + "#9e6c00ff", + "#2e2000e0", + ], + dark: [ + "#14120bff", + "#1b180fff", + "#2d2305ff", + "#362b00ff", + "#433500ff", + "#524202ff", + "#665417ff", + "#836a21ff", + "#ffe629ff", + "#ffff57ff", + "#f5e147ff", + "#f6eeb4ff", + ], + dark_alpha: [ + "#d1510004", + "#f9b4000b", + "#ffaa001e", + "#fdb70028", + "#febb0036", + "#fec40046", + "#fdcb225c", + "#fdca327b", + "#ffe629ff", + "#ffff57ff", + "#fee949f5", + "#fef6baf6", + ], + } +} + +fn amber() -> DefaultColorScaleSet { + DefaultColorScaleSet { + scale: ColorScaleName::Amber, + light: [ + "#fefdfbff", + "#fefbe9ff", + "#fff7c2ff", + "#ffee9cff", + "#fbe577ff", + "#f3d673ff", + "#e9c162ff", + "#e2a336ff", + "#ffc53dff", + "#ffba18ff", + "#ab6400ff", + "#4f3422ff", + ], + light_alpha: [ + "#c0800004", + "#f4d10016", + "#ffde003d", + "#ffd40063", + "#f8cf0088", + "#eab5008c", + "#dc9b009d", + "#da8a00c9", + "#ffb300c2", + "#ffb300e7", + "#ab6400ff", + "#341500dd", + ], + dark: [ + "#16120cff", + "#1d180fff", + "#302008ff", + "#3f2700ff", + "#4d3000ff", + "#5c3d05ff", + "#714f19ff", + "#8f6424ff", + "#ffc53dff", + "#ffd60aff", + "#ffca16ff", + "#ffe7b3ff", + ], + dark_alpha: [ + "#e63c0006", + "#fd9b000d", + "#fa820022", + "#fc820032", + "#fd8b0041", + "#fd9b0051", + "#ffab2567", + "#ffae3587", + "#ffc53dff", + "#ffd60aff", + "#ffca16ff", + "#ffe7b3ff", + ], + } +} + +fn orange() -> DefaultColorScaleSet { + DefaultColorScaleSet { + scale: ColorScaleName::Orange, + light: [ + "#fefcfbff", + "#fff7edff", + "#ffefd6ff", + "#ffdfb5ff", + "#ffd19aff", + "#ffc182ff", + "#f5ae73ff", + "#ec9455ff", + "#f76b15ff", + "#ef5f00ff", + "#cc4e00ff", + "#582d1dff", + ], + light_alpha: [ + "#c0400004", + "#ff8e0012", + "#ff9c0029", + "#ff91014a", + "#ff8b0065", + "#ff81007d", + "#ed6c008c", + "#e35f00aa", + "#f65e00ea", + "#ef5f00ff", + "#cc4e00ff", + "#431200e2", + ], + dark: [ + "#17120eff", + "#1e160fff", + "#331e0bff", + "#462100ff", + "#562800ff", + "#66350cff", + "#7e451dff", + "#a35829ff", + "#f76b15ff", + "#ff801fff", + "#ffa057ff", + "#ffe0c2ff", + ], + dark_alpha: [ + "#ec360007", + "#fe6d000e", + "#fb6a0025", + "#ff590039", + "#ff61004a", + "#fd75045c", + "#ff832c75", + "#fe84389d", + "#fe6d15f7", + "#ff801fff", + "#ffa057ff", + "#ffe0c2ff", + ], + } +} + +fn tomato() -> DefaultColorScaleSet { + DefaultColorScaleSet { + scale: ColorScaleName::Tomato, + light: [ + "#fffcfcff", + "#fff8f7ff", + "#feebe7ff", + "#ffdcd3ff", + "#ffcdc2ff", + "#fdbdafff", + "#f5a898ff", + "#ec8e7bff", + "#e54d2eff", + "#dd4425ff", + "#d13415ff", + "#5c271fff", + ], + light_alpha: [ + "#ff000003", + "#ff200008", + "#f52b0018", + "#ff35002c", + "#ff2e003d", + "#f92d0050", + "#e7280067", + "#db250084", + "#df2600d1", + "#d72400da", + "#cd2200ea", + "#460900e0", + ], + dark: [ + "#181111ff", + "#1f1513ff", + "#391714ff", + "#4e1511ff", + "#5e1c16ff", + "#6e2920ff", + "#853a2dff", + "#ac4d39ff", + "#e54d2eff", + "#ec6142ff", + "#ff977dff", + "#fbd3cbff", + ], + dark_alpha: [ + "#f1121208", + "#ff55330f", + "#ff35232b", + "#fd201142", + "#fe332153", + "#ff4f3864", + "#fd644a7d", + "#fe6d4ea7", + "#fe5431e4", + "#ff6847eb", + "#ff977dff", + "#ffd6cefb", + ], + } +} + +fn red() -> DefaultColorScaleSet { + DefaultColorScaleSet { + scale: ColorScaleName::Red, + light: [ + "#fffcfcff", + "#fff7f7ff", + "#feebecff", + "#ffdbdcff", + "#ffcdceff", + "#fdbdbeff", + "#f4a9aaff", + "#eb8e90ff", + "#e5484dff", + "#dc3e42ff", + "#ce2c31ff", + "#641723ff", + ], + light_alpha: [ + "#ff000003", + "#ff000008", + "#f3000d14", + "#ff000824", + "#ff000632", + "#f8000442", + "#df000356", + "#d2000571", + "#db0007b7", + "#d10005c1", + "#c40006d3", + "#55000de8", + ], + dark: [ + "#191111ff", + "#201314ff", + "#3b1219ff", + "#500f1cff", + "#611623ff", + "#72232dff", + "#8c333aff", + "#b54548ff", + "#e5484dff", + "#ec5d5eff", + "#ff9592ff", + "#ffd1d9ff", + ], + dark_alpha: [ + "#f4121209", + "#f22f3e11", + "#ff173f2d", + "#fe0a3b44", + "#ff204756", + "#ff3e5668", + "#ff536184", + "#ff5d61b0", + "#fe4e54e4", + "#ff6465eb", + "#ff9592ff", + "#ffd1d9ff", + ], + } +} + +fn ruby() -> DefaultColorScaleSet { + DefaultColorScaleSet { + scale: ColorScaleName::Ruby, + light: [ + "#fffcfdff", + "#fff7f8ff", + "#feeaedff", + "#ffdce1ff", + "#ffced6ff", + "#f8bfc8ff", + "#efacb8ff", + "#e592a3ff", + "#e54666ff", + "#dc3b5dff", + "#ca244dff", + "#64172bff", + ], + light_alpha: [ + "#ff005503", + "#ff002008", + "#f3002515", + "#ff002523", + "#ff002a31", + "#e4002440", + "#ce002553", + "#c300286d", + "#db002cb9", + "#d2002cc4", + "#c10030db", + "#550016e8", + ], + dark: [ + "#191113ff", + "#1e1517ff", + "#3a141eff", + "#4e1325ff", + "#5e1a2eff", + "#6f2539ff", + "#883447ff", + "#b3445aff", + "#e54666ff", + "#ec5a72ff", + "#ff949dff", + "#fed2e1ff", + ], + dark_alpha: [ + "#f4124a09", + "#fe5a7f0e", + "#ff235d2c", + "#fd195e42", + "#fe2d6b53", + "#ff447665", + "#ff577d80", + "#ff5c7cae", + "#fe4c70e4", + "#ff617beb", + "#ff949dff", + "#ffd3e2fe", + ], + } +} + +fn crimson() -> DefaultColorScaleSet { + DefaultColorScaleSet { + scale: ColorScaleName::Crimson, + light: [ + "#fffcfdff", + "#fef7f9ff", + "#ffe9f0ff", + "#fedce7ff", + "#faceddff", + "#f3bed1ff", + "#eaacc3ff", + "#e093b2ff", + "#e93d82ff", + "#df3478ff", + "#cb1d63ff", + "#621639ff", + ], + light_alpha: [ + "#ff005503", + "#e0004008", + "#ff005216", + "#f8005123", + "#e5004f31", + "#d0004b41", + "#bf004753", + "#b6004a6c", + "#e2005bc2", + "#d70056cb", + "#c4004fe2", + "#530026e9", + ], + dark: [ + "#191114ff", + "#201318ff", + "#381525ff", + "#4d122fff", + "#5c1839ff", + "#6d2545ff", + "#873356ff", + "#b0436eff", + "#e93d82ff", + "#ee518aff", + "#ff92adff", + "#fdd3e8ff", + ], + dark_alpha: [ + "#f4126709", + "#f22f7a11", + "#fe2a8b2a", + "#fd158741", + "#fd278f51", + "#fe459763", + "#fd559b7f", + "#fe5b9bab", + "#fe418de8", + "#ff5693ed", + "#ff92adff", + "#ffd5eafd", + ], + } +} + +fn pink() -> DefaultColorScaleSet { + DefaultColorScaleSet { + scale: ColorScaleName::Pink, + light: [ + "#fffcfeff", + "#fef7fbff", + "#fee9f5ff", + "#fbdcefff", + "#f6cee7ff", + "#efbfddff", + "#e7acd0ff", + "#dd93c2ff", + "#d6409fff", + "#cf3897ff", + "#c2298aff", + "#651249ff", + ], + light_alpha: [ + "#ff00aa03", + "#e0008008", + "#f4008c16", + "#e2008b23", + "#d1008331", + "#c0007840", + "#b6006f53", + "#af006f6c", + "#c8007fbf", + "#c2007ac7", + "#b60074d6", + "#59003bed", + ], + dark: [ + "#191117ff", + "#21121dff", + "#37172fff", + "#4b143dff", + "#591c47ff", + "#692955ff", + "#833869ff", + "#a84885ff", + "#d6409fff", + "#de51a8ff", + "#ff8dccff", + "#fdd1eaff", + ], + dark_alpha: [ + "#f412bc09", + "#f420bb12", + "#fe37cc29", + "#fc1ec43f", + "#fd35c24e", + "#fd51c75f", + "#fd62c87b", + "#ff68c8a2", + "#fe49bcd4", + "#ff5cc0dc", + "#ff8dccff", + "#ffd3ecfd", + ], + } +} + +fn plum() -> DefaultColorScaleSet { + DefaultColorScaleSet { + scale: ColorScaleName::Plum, + light: [ + "#fefcffff", + "#fdf7fdff", + "#fbebfbff", + "#f7def8ff", + "#f2d1f3ff", + "#e9c2ecff", + "#deade3ff", + "#cf91d8ff", + "#ab4abaff", + "#a144afff", + "#953ea3ff", + "#53195dff", + ], + light_alpha: [ + "#aa00ff03", + "#c000c008", + "#cc00cc14", + "#c200c921", + "#b700bd2e", + "#a400b03d", + "#9900a852", + "#9000a56e", + "#89009eb5", + "#7f0092bb", + "#730086c1", + "#40004be6", + ], + dark: [ + "#181118ff", + "#201320ff", + "#351a35ff", + "#451d47ff", + "#512454ff", + "#5e3061ff", + "#734079ff", + "#92549cff", + "#ab4abaff", + "#b658c4ff", + "#e796f3ff", + "#f4d4f4ff", + ], + dark_alpha: [ + "#f112f108", + "#f22ff211", + "#fd4cfd27", + "#f646ff3a", + "#f455ff48", + "#f66dff56", + "#f07cfd70", + "#ee84ff95", + "#e961feb6", + "#ed70ffc0", + "#f19cfef3", + "#feddfef4", + ], + } +} + +fn purple() -> DefaultColorScaleSet { + DefaultColorScaleSet { + scale: ColorScaleName::Purple, + light: [ + "#fefcfeff", + "#fbf7feff", + "#f7edfeff", + "#f2e2fcff", + "#ead5f9ff", + "#e0c4f4ff", + "#d1afecff", + "#be93e4ff", + "#8e4ec6ff", + "#8347b9ff", + "#8145b5ff", + "#402060ff", + ], + light_alpha: [ + "#aa00aa03", + "#8000e008", + "#8e00f112", + "#8d00e51d", + "#8000db2a", + "#7a01d03b", + "#6d00c350", + "#6600c06c", + "#5c00adb1", + "#53009eb8", + "#52009aba", + "#250049df", + ], + dark: [ + "#18111bff", + "#1e1523ff", + "#301c3bff", + "#3d224eff", + "#48295cff", + "#54346bff", + "#664282ff", + "#8457aaff", + "#8e4ec6ff", + "#9a5cd0ff", + "#d19dffff", + "#ecd9faff", + ], + dark_alpha: [ + "#b412f90b", + "#b744f714", + "#c150ff2d", + "#bb53fd42", + "#be5cfd51", + "#c16dfd61", + "#c378fd7a", + "#c47effa4", + "#b661ffc2", + "#bc6fffcd", + "#d19dffff", + "#f1ddfffa", + ], + } +} + +fn violet() -> DefaultColorScaleSet { + DefaultColorScaleSet { + scale: ColorScaleName::Violet, + light: [ + "#fdfcfeff", + "#faf8ffff", + "#f4f0feff", + "#ebe4ffff", + "#e1d9ffff", + "#d4cafeff", + "#c2b5f5ff", + "#aa99ecff", + "#6e56cfff", + "#654dc4ff", + "#6550b9ff", + "#2f265fff", + ], + light_alpha: [ + "#5500aa03", + "#4900ff07", + "#4400ee0f", + "#4300ff1b", + "#3600ff26", + "#3100fb35", + "#2d01dd4a", + "#2b00d066", + "#2400b7a9", + "#2300abb2", + "#1f0099af", + "#0b0043d9", + ], + dark: [ + "#14121fff", + "#1b1525ff", + "#291f43ff", + "#33255bff", + "#3c2e69ff", + "#473876ff", + "#56468bff", + "#6958adff", + "#6e56cfff", + "#7d66d9ff", + "#baa7ffff", + "#e2ddfeff", + ], + dark_alpha: [ + "#4422ff0f", + "#853ff916", + "#8354fe36", + "#7d51fd50", + "#845ffd5f", + "#8f6cfd6d", + "#9879ff83", + "#977dfea8", + "#8668ffcc", + "#9176fed7", + "#baa7ffff", + "#e3defffe", + ], + } +} + +fn iris() -> DefaultColorScaleSet { + DefaultColorScaleSet { + scale: ColorScaleName::Iris, + light: [ + "#fdfdffff", + "#f8f8ffff", + "#f0f1feff", + "#e6e7ffff", + "#dadcffff", + "#cbcdffff", + "#b8baf8ff", + "#9b9ef0ff", + "#5b5bd6ff", + "#5151cdff", + "#5753c6ff", + "#272962ff", + ], + light_alpha: [ + "#0000ff02", + "#0000ff07", + "#0011ee0f", + "#000bff19", + "#000eff25", + "#000aff34", + "#0008e647", + "#0008d964", + "#0000c0a4", + "#0000b6ae", + "#0600abac", + "#000246d8", + ], + dark: [ + "#13131eff", + "#171625ff", + "#202248ff", + "#262a65ff", + "#303374ff", + "#3d3e82ff", + "#4a4a95ff", + "#5958b1ff", + "#5b5bd6ff", + "#6e6adeff", + "#b1a9ffff", + "#e0dffeff", + ], + dark_alpha: [ + "#3636fe0e", + "#564bf916", + "#525bff3b", + "#4d58ff5a", + "#5b62fd6b", + "#6d6ffd7a", + "#7777fe8e", + "#7b7afeac", + "#6a6afed4", + "#7d79ffdc", + "#b1a9ffff", + "#e1e0fffe", + ], + } +} + +fn indigo() -> DefaultColorScaleSet { + DefaultColorScaleSet { + scale: ColorScaleName::Indigo, + light: [ + "#fdfdfeff", + "#f7f9ffff", + "#edf2feff", + "#e1e9ffff", + "#d2deffff", + "#c1d0ffff", + "#abbdf9ff", + "#8da4efff", + "#3e63ddff", + "#3358d4ff", + "#3a5bc7ff", + "#1f2d5cff", + ], + light_alpha: [ + "#00008002", + "#0040ff08", + "#0047f112", + "#0044ff1e", + "#0044ff2d", + "#003eff3e", + "#0037ed54", + "#0034dc72", + "#0031d2c1", + "#002ec9cc", + "#002bb7c5", + "#001046e0", + ], + dark: [ + "#11131fff", + "#141726ff", + "#182449ff", + "#1d2e62ff", + "#253974ff", + "#304384ff", + "#3a4f97ff", + "#435db1ff", + "#3e63ddff", + "#5472e4ff", + "#9eb1ffff", + "#d6e1ffff", + ], + dark_alpha: [ + "#1133ff0f", + "#3354fa17", + "#2f62ff3c", + "#3566ff57", + "#4171fd6b", + "#5178fd7c", + "#5a7fff90", + "#5b81feac", + "#4671ffdb", + "#5c7efee3", + "#9eb1ffff", + "#d6e1ffff", + ], + } +} + +fn blue() -> DefaultColorScaleSet { + DefaultColorScaleSet { + scale: ColorScaleName::Blue, + light: [ + "#fbfdffff", + "#f4faffff", + "#e6f4feff", + "#d5efffff", + "#c2e5ffff", + "#acd8fcff", + "#8ec8f6ff", + "#5eb1efff", + "#0090ffff", + "#0588f0ff", + "#0d74ceff", + "#113264ff", + ], + light_alpha: [ + "#0080ff04", + "#008cff0b", + "#008ff519", + "#009eff2a", + "#0093ff3d", + "#0088f653", + "#0083eb71", + "#0084e6a1", + "#0090ffff", + "#0086f0fa", + "#006dcbf2", + "#002359ee", + ], + dark: [ + "#0d1520ff", + "#111927ff", + "#0d2847ff", + "#003362ff", + "#004074ff", + "#104d87ff", + "#205d9eff", + "#2870bdff", + "#0090ffff", + "#3b9effff", + "#70b8ffff", + "#c2e6ffff", + ], + dark_alpha: [ + "#004df211", + "#1166fb18", + "#0077ff3a", + "#0075ff57", + "#0081fd6b", + "#0f89fd7f", + "#2a91fe98", + "#3094feb9", + "#0090ffff", + "#3b9effff", + "#70b8ffff", + "#c2e6ffff", + ], + } +} + +fn cyan() -> DefaultColorScaleSet { + DefaultColorScaleSet { + scale: ColorScaleName::Cyan, + light: [ + "#fafdfeff", + "#f2fafbff", + "#def7f9ff", + "#caf1f6ff", + "#b5e9f0ff", + "#9ddde7ff", + "#7dcedcff", + "#3db9cfff", + "#00a2c7ff", + "#0797b9ff", + "#107d98ff", + "#0d3c48ff", + ], + light_alpha: [ + "#0099cc05", + "#009db10d", + "#00c2d121", + "#00bcd435", + "#01b4cc4a", + "#00a7c162", + "#009fbb82", + "#00a3c0c2", + "#00a2c7ff", + "#0094b7f8", + "#007491ef", + "#00323ef2", + ], + dark: [ + "#0b161aff", + "#101b20ff", + "#082c36ff", + "#003848ff", + "#004558ff", + "#045468ff", + "#12677eff", + "#11809cff", + "#00a2c7ff", + "#23afd0ff", + "#4ccce6ff", + "#b6ecf7ff", + ], + dark_alpha: [ + "#0091f70a", + "#02a7f211", + "#00befd28", + "#00baff3b", + "#00befd4d", + "#00c7fd5e", + "#14cdff75", + "#11cfff95", + "#00cfffc3", + "#28d6ffcd", + "#52e1fee5", + "#bbf3fef7", + ], + } +} + +fn teal() -> DefaultColorScaleSet { + DefaultColorScaleSet { + scale: ColorScaleName::Teal, + light: [ + "#fafefdff", + "#f3fbf9ff", + "#e0f8f3ff", + "#ccf3eaff", + "#b8eae0ff", + "#a1ded2ff", + "#83cdc1ff", + "#53b9abff", + "#12a594ff", + "#0d9b8aff", + "#008573ff", + "#0d3d38ff", + ], + light_alpha: [ + "#00cc9905", + "#00aa800c", + "#00c69d1f", + "#00c39633", + "#00b49047", + "#00a6855e", + "#0099807c", + "#009783ac", + "#009e8ced", + "#009684f2", + "#008573ff", + "#00332df2", + ], + dark: [ + "#0d1514ff", + "#111c1bff", + "#0d2d2aff", + "#023b37ff", + "#084843ff", + "#145750ff", + "#1c6961ff", + "#207e73ff", + "#12a594ff", + "#0eb39eff", + "#0bd8b6ff", + "#adf0ddff", + ], + dark_alpha: [ + "#00deab05", + "#12fbe60c", + "#00ffe61e", + "#00ffe92d", + "#00ffea3b", + "#1cffe84b", + "#2efde85f", + "#32ffe775", + "#13ffe49f", + "#0dffe0ae", + "#0afed5d6", + "#b8ffebef", + ], + } +} + +fn jade() -> DefaultColorScaleSet { + DefaultColorScaleSet { + scale: ColorScaleName::Jade, + light: [ + "#fbfefdff", + "#f4fbf7ff", + "#e6f7edff", + "#d6f1e3ff", + "#c3e9d7ff", + "#acdec8ff", + "#8bceb6ff", + "#56ba9fff", + "#29a383ff", + "#26997bff", + "#208368ff", + "#1d3b31ff", + ], + light_alpha: [ + "#00c08004", + "#00a3460b", + "#00ae4819", + "#00a85129", + "#00a2553c", + "#009a5753", + "#00945f74", + "#00976ea9", + "#00916bd6", + "#008764d9", + "#007152df", + "#002217e2", + ], + dark: [ + "#0d1512ff", + "#121c18ff", + "#0f2e22ff", + "#0b3b2cff", + "#114837ff", + "#1b5745ff", + "#246854ff", + "#2a7e68ff", + "#29a383ff", + "#27b08bff", + "#1fd8a4ff", + "#adf0d4ff", + ], + dark_alpha: [ + "#00de4505", + "#27fba60c", + "#02f99920", + "#00ffaa2d", + "#11ffb63b", + "#34ffc24b", + "#45fdc75e", + "#48ffcf75", + "#38feca9d", + "#31fec7ab", + "#21fec0d6", + "#b8ffe1ef", + ], + } +} + +fn green() -> DefaultColorScaleSet { + DefaultColorScaleSet { + scale: ColorScaleName::Green, + light: [ + "#fbfefcff", + "#f4fbf6ff", + "#e6f6ebff", + "#d6f1dfff", + "#c4e8d1ff", + "#adddc0ff", + "#8eceaaff", + "#5bb98bff", + "#30a46cff", + "#2b9a66ff", + "#218358ff", + "#193b2dff", + ], + light_alpha: [ + "#00c04004", + "#00a32f0b", + "#00a43319", + "#00a83829", + "#019c393b", + "#00963c52", + "#00914071", + "#00924ba4", + "#008f4acf", + "#008647d4", + "#00713fde", + "#002616e6", + ], + dark: [ + "#0e1512ff", + "#121b17ff", + "#132d21ff", + "#113b29ff", + "#174933ff", + "#20573eff", + "#28684aff", + "#2f7c57ff", + "#30a46cff", + "#33b074ff", + "#3dd68cff", + "#b1f1cbff", + ], + dark_alpha: [ + "#00de4505", + "#29f99d0b", + "#22ff991e", + "#11ff992d", + "#2bffa23c", + "#44ffaa4b", + "#50fdac5e", + "#54ffad73", + "#44ffa49e", + "#43fea4ab", + "#46fea5d4", + "#bbffd7f0", + ], + } +} + +fn grass() -> DefaultColorScaleSet { + DefaultColorScaleSet { + scale: ColorScaleName::Grass, + light: [ + "#fbfefbff", + "#f5fbf5ff", + "#e9f6e9ff", + "#daf1dbff", + "#c9e8caff", + "#b2ddb5ff", + "#94ce9aff", + "#65ba74ff", + "#46a758ff", + "#3e9b4fff", + "#2a7e3bff", + "#203c25ff", + ], + light_alpha: [ + "#00c00004", + "#0099000a", + "#00970016", + "#009f0725", + "#00930536", + "#008f0a4d", + "#018b0f6b", + "#008d199a", + "#008619b9", + "#007b17c1", + "#006514d5", + "#002006df", + ], + dark: [ + "#0e1511ff", + "#141a15ff", + "#1b2a1eff", + "#1d3a24ff", + "#25482dff", + "#2d5736ff", + "#366740ff", + "#3e7949ff", + "#46a758ff", + "#53b365ff", + "#71d083ff", + "#c2f0c2ff", + ], + dark_alpha: [ + "#00de1205", + "#5ef7780a", + "#70fe8c1b", + "#57ff802c", + "#68ff8b3b", + "#71ff8f4b", + "#77fd925d", + "#77fd9070", + "#65ff82a1", + "#72ff8dae", + "#89ff9fcd", + "#ceffceef", + ], + } +} + +fn lime() -> DefaultColorScaleSet { + DefaultColorScaleSet { + scale: ColorScaleName::Lime, + light: [ + "#fcfdfaff", + "#f8faf3ff", + "#eef6d6ff", + "#e2f0bdff", + "#d3e7a6ff", + "#c2da91ff", + "#abc978ff", + "#8db654ff", + "#bdee63ff", + "#b0e64cff", + "#5c7c2fff", + "#37401cff", + ], + light_alpha: [ + "#66990005", + "#6b95000c", + "#96c80029", + "#8fc60042", + "#81bb0059", + "#72aa006e", + "#61990087", + "#559200ab", + "#93e4009c", + "#8fdc00b3", + "#375f00d0", + "#1e2900e3", + ], + dark: [ + "#11130cff", + "#151a10ff", + "#1f2917ff", + "#29371dff", + "#334423ff", + "#3d522aff", + "#496231ff", + "#577538ff", + "#bdee63ff", + "#d4ff70ff", + "#bde56cff", + "#e3f7baff", + ], + dark_alpha: [ + "#11bb0003", + "#78f7000a", + "#9bfd4c1a", + "#a7fe5c29", + "#affe6537", + "#b2fe6d46", + "#b6ff6f57", + "#b6fd6d6c", + "#caff69ed", + "#d4ff70ff", + "#d1fe77e4", + "#e9febff7", + ], + } +} + +fn mint() -> DefaultColorScaleSet { + DefaultColorScaleSet { + scale: ColorScaleName::Mint, + light: [ + "#f9fefdff", + "#f2fbf9ff", + "#ddf9f2ff", + "#c8f4e9ff", + "#b3ecdeff", + "#9ce0d0ff", + "#7ecfbdff", + "#4cbba5ff", + "#86ead4ff", + "#7de0cbff", + "#027864ff", + "#16433cff", + ], + light_alpha: [ + "#00d5aa06", + "#00b18a0d", + "#00d29e22", + "#00cc9937", + "#00c0914c", + "#00b08663", + "#00a17d81", + "#009e7fb3", + "#00d3a579", + "#00c39982", + "#007763fd", + "#00312ae9", + ], + dark: [ + "#0e1515ff", + "#0f1b1bff", + "#092c2bff", + "#003a38ff", + "#004744ff", + "#105650ff", + "#1e685fff", + "#277f70ff", + "#86ead4ff", + "#a8f5e5ff", + "#58d5baff", + "#c4f5e1ff", + ], + dark_alpha: [ + "#00dede05", + "#00f9f90b", + "#00fff61d", + "#00fff42c", + "#00fff23a", + "#0effeb4a", + "#34fde55e", + "#41ffdf76", + "#92ffe7e9", + "#aefeedf5", + "#67ffded2", + "#cbfee9f5", + ], + } +} + +fn sky() -> DefaultColorScaleSet { + DefaultColorScaleSet { + scale: ColorScaleName::Sky, + light: [ + "#f9feffff", + "#f1fafdff", + "#e1f6fdff", + "#d1f0faff", + "#bee7f5ff", + "#a9daedff", + "#8dcae3ff", + "#60b3d7ff", + "#7ce2feff", + "#74daf8ff", + "#00749eff", + "#1d3e56ff", + ], + light_alpha: [ + "#00d5ff06", + "#00a4db0e", + "#00b3ee1e", + "#00ace42e", + "#00a1d841", + "#0092ca56", + "#0089c172", + "#0085bf9f", + "#00c7fe83", + "#00bcf38b", + "#00749eff", + "#002540e2", + ], + dark: [ + "#0d141fff", + "#111a27ff", + "#112840ff", + "#113555ff", + "#154467ff", + "#1b537bff", + "#1f6692ff", + "#197caeff", + "#7ce2feff", + "#a8eeffff", + "#75c7f0ff", + "#c2f3ffff", + ], + dark_alpha: [ + "#0044ff0f", + "#1171fb18", + "#1184fc33", + "#128fff49", + "#1c9dfd5d", + "#28a5ff72", + "#2badfe8b", + "#1db2fea9", + "#7ce3fffe", + "#a8eeffff", + "#7cd3ffef", + "#c2f3ffff", + ], + } +} + +fn black() -> DefaultColorScaleSet { + DefaultColorScaleSet { + scale: ColorScaleName::Black, + light: [ + "#0000000d", + "#0000001a", + "#00000026", + "#00000033", + "#0000004d", + "#00000066", + "#00000080", + "#00000099", + "#000000b3", + "#000000cc", + "#000000e6", + "#000000f2", + ], + light_alpha: [ + "#0000000d", + "#0000001a", + "#00000026", + "#00000033", + "#0000004d", + "#00000066", + "#00000080", + "#00000099", + "#000000b3", + "#000000cc", + "#000000e6", + "#000000f2", + ], + dark: [ + "#0000000d", + "#0000001a", + "#00000026", + "#00000033", + "#0000004d", + "#00000066", + "#00000080", + "#00000099", + "#000000b3", + "#000000cc", + "#000000e6", + "#000000f2", + ], + dark_alpha: [ + "#0000000d", + "#0000001a", + "#00000026", + "#00000033", + "#0000004d", + "#00000066", + "#00000080", + "#00000099", + "#000000b3", + "#000000cc", + "#000000e6", + "#000000f2", + ], + } +} + +fn white() -> DefaultColorScaleSet { + DefaultColorScaleSet { + scale: ColorScaleName::White, + light: [ + "#ffffff0d", + "#ffffff1a", + "#ffffff26", + "#ffffff33", + "#ffffff4d", + "#ffffff66", + "#ffffff80", + "#ffffff99", + "#ffffffb3", + "#ffffffcc", + "#ffffffe6", + "#fffffff2", + ], + light_alpha: [ + "#ffffff0d", + "#ffffff1a", + "#ffffff26", + "#ffffff33", + "#ffffff4d", + "#ffffff66", + "#ffffff80", + "#ffffff99", + "#ffffffb3", + "#ffffffcc", + "#ffffffe6", + "#fffffff2", + ], + dark: [ + "#ffffff0d", + "#ffffff1a", + "#ffffff26", + "#ffffff33", + "#ffffff4d", + "#ffffff66", + "#ffffff80", + "#ffffff99", + "#ffffffb3", + "#ffffffcc", + "#ffffffe6", + "#fffffff2", + ], + dark_alpha: [ + "#ffffff0d", + "#ffffff1a", + "#ffffff26", + "#ffffff33", + "#ffffff4d", + "#ffffff66", + "#ffffff80", + "#ffffff99", + "#ffffffb3", + "#ffffffcc", + "#ffffffe6", + "#fffffff2", + ], + } +} diff --git a/crates/theme2/src/registry.rs b/crates/theme2/src/registry.rs index b98a4db722..eec82ef5a7 100644 --- a/crates/theme2/src/registry.rs +++ b/crates/theme2/src/registry.rs @@ -1,7 +1,4 @@ -use crate::{ - themes::{one_dark, rose_pine, rose_pine_dawn, rose_pine_moon, sandcastle}, - Theme, ThemeMetadata, -}; +use crate::{themes, Theme, ThemeMetadata}; use anyhow::{anyhow, Result}; use gpui2::SharedString; use std::{collections::HashMap, sync::Arc}; @@ -41,11 +38,45 @@ impl Default for ThemeRegistry { }; this.insert_themes([ - one_dark(), - rose_pine(), - rose_pine_dawn(), - rose_pine_moon(), - sandcastle(), + themes::andromeda(), + themes::atelier_cave_dark(), + themes::atelier_cave_light(), + themes::atelier_dune_dark(), + themes::atelier_dune_light(), + themes::atelier_estuary_dark(), + themes::atelier_estuary_light(), + themes::atelier_forest_dark(), + themes::atelier_forest_light(), + themes::atelier_heath_dark(), + themes::atelier_heath_light(), + themes::atelier_lakeside_dark(), + themes::atelier_lakeside_light(), + themes::atelier_plateau_dark(), + themes::atelier_plateau_light(), + themes::atelier_savanna_dark(), + themes::atelier_savanna_light(), + themes::atelier_seaside_dark(), + themes::atelier_seaside_light(), + themes::atelier_sulphurpool_dark(), + themes::atelier_sulphurpool_light(), + themes::ayu_dark(), + themes::ayu_light(), + themes::ayu_mirage(), + themes::gruvbox_dark(), + themes::gruvbox_dark_hard(), + themes::gruvbox_dark_soft(), + themes::gruvbox_light(), + themes::gruvbox_light_hard(), + themes::gruvbox_light_soft(), + themes::one_dark(), + themes::one_light(), + themes::rose_pine(), + themes::rose_pine_dawn(), + themes::rose_pine_moon(), + themes::sandcastle(), + themes::solarized_dark(), + themes::solarized_light(), + themes::summercamp(), ]); this diff --git a/crates/theme2/src/scale.rs b/crates/theme2/src/scale.rs new file mode 100644 index 0000000000..22a607bf07 --- /dev/null +++ b/crates/theme2/src/scale.rs @@ -0,0 +1,164 @@ +use gpui2::{AppContext, Hsla}; +use indexmap::IndexMap; + +use crate::{theme, Appearance}; + +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum ColorScaleName { + Gray, + Mauve, + Slate, + Sage, + Olive, + Sand, + Gold, + Bronze, + Brown, + Yellow, + Amber, + Orange, + Tomato, + Red, + Ruby, + Crimson, + Pink, + Plum, + Purple, + Violet, + Iris, + Indigo, + Blue, + Cyan, + Teal, + Jade, + Green, + Grass, + Lime, + Mint, + Sky, + Black, + White, +} + +impl std::fmt::Display for ColorScaleName { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "{}", + match self { + Self::Gray => "Gray", + Self::Mauve => "Mauve", + Self::Slate => "Slate", + Self::Sage => "Sage", + Self::Olive => "Olive", + Self::Sand => "Sand", + Self::Gold => "Gold", + Self::Bronze => "Bronze", + Self::Brown => "Brown", + Self::Yellow => "Yellow", + Self::Amber => "Amber", + Self::Orange => "Orange", + Self::Tomato => "Tomato", + Self::Red => "Red", + Self::Ruby => "Ruby", + Self::Crimson => "Crimson", + Self::Pink => "Pink", + Self::Plum => "Plum", + Self::Purple => "Purple", + Self::Violet => "Violet", + Self::Iris => "Iris", + Self::Indigo => "Indigo", + Self::Blue => "Blue", + Self::Cyan => "Cyan", + Self::Teal => "Teal", + Self::Jade => "Jade", + Self::Green => "Green", + Self::Grass => "Grass", + Self::Lime => "Lime", + Self::Mint => "Mint", + Self::Sky => "Sky", + Self::Black => "Black", + Self::White => "White", + } + ) + } +} + +pub type ColorScale = [Hsla; 12]; + +pub type ColorScales = IndexMap; + +/// A one-based step in a [`ColorScale`]. +pub type ColorScaleStep = usize; + +pub struct ColorScaleSet { + name: ColorScaleName, + light: ColorScale, + dark: ColorScale, + light_alpha: ColorScale, + dark_alpha: ColorScale, +} + +impl ColorScaleSet { + pub fn new( + name: ColorScaleName, + light: ColorScale, + light_alpha: ColorScale, + dark: ColorScale, + dark_alpha: ColorScale, + ) -> Self { + Self { + name, + light, + light_alpha, + dark, + dark_alpha, + } + } + + pub fn name(&self) -> String { + self.name.to_string() + } + + pub fn light(&self, step: ColorScaleStep) -> Hsla { + self.light[step - 1] + } + + pub fn light_alpha(&self, step: ColorScaleStep) -> Hsla { + self.light_alpha[step - 1] + } + + pub fn dark(&self, step: ColorScaleStep) -> Hsla { + self.dark[step - 1] + } + + pub fn dark_alpha(&self, step: ColorScaleStep) -> Hsla { + self.dark_alpha[step - 1] + } + + fn current_appearance(cx: &AppContext) -> Appearance { + let theme = theme(cx); + if theme.metadata.is_light { + Appearance::Light + } else { + Appearance::Dark + } + } + + pub fn step(&self, cx: &AppContext, step: ColorScaleStep) -> Hsla { + let appearance = Self::current_appearance(cx); + + match appearance { + Appearance::Light => self.light(step), + Appearance::Dark => self.dark(step), + } + } + + pub fn step_alpha(&self, cx: &AppContext, step: ColorScaleStep) -> Hsla { + let appearance = Self::current_appearance(cx); + match appearance { + Appearance::Light => self.light_alpha(step), + Appearance::Dark => self.dark_alpha(step), + } + } +} diff --git a/crates/theme2/src/theme2.rs b/crates/theme2/src/theme2.rs index 9a7d58a6c7..9425593070 100644 --- a/crates/theme2/src/theme2.rs +++ b/crates/theme2/src/theme2.rs @@ -1,14 +1,24 @@ +mod default; mod registry; +mod scale; mod settings; mod themes; +pub use default::*; pub use registry::*; +pub use scale::*; pub use settings::*; use gpui2::{AppContext, HighlightStyle, Hsla, SharedString}; use settings2::Settings; use std::sync::Arc; +#[derive(Debug, Clone, PartialEq)] +pub enum Appearance { + Light, + Dark, +} + pub fn init(cx: &mut AppContext) { cx.set_global(ThemeRegistry::default()); ThemeSettings::register(cx); @@ -18,6 +28,10 @@ pub fn active_theme<'a>(cx: &'a AppContext) -> &'a Arc { &ThemeSettings::get_global(cx).active_theme } +pub fn theme(cx: &AppContext) -> Arc { + active_theme(cx).clone() +} + pub struct Theme { pub metadata: ThemeMetadata, diff --git a/crates/theme2/src/themes/andromeda.rs b/crates/theme2/src/themes/andromeda.rs new file mode 100644 index 0000000000..6afd7edd4d --- /dev/null +++ b/crates/theme2/src/themes/andromeda.rs @@ -0,0 +1,130 @@ +use gpui2::rgba; + +use crate::{PlayerTheme, SyntaxTheme, Theme, ThemeMetadata}; + +pub fn andromeda() -> Theme { + Theme { + metadata: ThemeMetadata { + name: "Andromeda".into(), + is_light: false, + }, + transparent: rgba(0x00000000).into(), + mac_os_traffic_light_red: rgba(0xec695eff).into(), + mac_os_traffic_light_yellow: rgba(0xf4bf4eff).into(), + mac_os_traffic_light_green: rgba(0x61c553ff).into(), + border: rgba(0x2b2f38ff).into(), + border_variant: rgba(0x2b2f38ff).into(), + border_focused: rgba(0x183934ff).into(), + border_transparent: rgba(0x00000000).into(), + elevated_surface: rgba(0x262933ff).into(), + surface: rgba(0x21242bff).into(), + background: rgba(0x262933ff).into(), + filled_element: rgba(0x262933ff).into(), + filled_element_hover: rgba(0xffffff1e).into(), + filled_element_active: rgba(0xffffff28).into(), + filled_element_selected: rgba(0x12231fff).into(), + filled_element_disabled: rgba(0x00000000).into(), + ghost_element: rgba(0x00000000).into(), + ghost_element_hover: rgba(0xffffff14).into(), + ghost_element_active: rgba(0xffffff1e).into(), + ghost_element_selected: rgba(0x12231fff).into(), + ghost_element_disabled: rgba(0x00000000).into(), + text: rgba(0xf7f7f8ff).into(), + text_muted: rgba(0xaca8aeff).into(), + text_placeholder: rgba(0xf82871ff).into(), + text_disabled: rgba(0x6b6b73ff).into(), + text_accent: rgba(0x10a793ff).into(), + icon_muted: rgba(0xaca8aeff).into(), + syntax: SyntaxTheme { + highlights: vec![ + ("emphasis".into(), rgba(0x10a793ff).into()), + ("punctuation.bracket".into(), rgba(0xd8d5dbff).into()), + ("attribute".into(), rgba(0x10a793ff).into()), + ("variable".into(), rgba(0xf7f7f8ff).into()), + ("predictive".into(), rgba(0x315f70ff).into()), + ("property".into(), rgba(0x10a793ff).into()), + ("variant".into(), rgba(0x10a793ff).into()), + ("embedded".into(), rgba(0xf7f7f8ff).into()), + ("string.special".into(), rgba(0xf29c14ff).into()), + ("keyword".into(), rgba(0x10a793ff).into()), + ("tag".into(), rgba(0x10a793ff).into()), + ("enum".into(), rgba(0xf29c14ff).into()), + ("link_text".into(), rgba(0xf29c14ff).into()), + ("primary".into(), rgba(0xf7f7f8ff).into()), + ("punctuation".into(), rgba(0xd8d5dbff).into()), + ("punctuation.special".into(), rgba(0xd8d5dbff).into()), + ("function".into(), rgba(0xfee56cff).into()), + ("number".into(), rgba(0x96df71ff).into()), + ("preproc".into(), rgba(0xf7f7f8ff).into()), + ("operator".into(), rgba(0xf29c14ff).into()), + ("constructor".into(), rgba(0x10a793ff).into()), + ("string.escape".into(), rgba(0xafabb1ff).into()), + ("string.special.symbol".into(), rgba(0xf29c14ff).into()), + ("string".into(), rgba(0xf29c14ff).into()), + ("comment".into(), rgba(0xafabb1ff).into()), + ("hint".into(), rgba(0x618399ff).into()), + ("type".into(), rgba(0x08e7c5ff).into()), + ("label".into(), rgba(0x10a793ff).into()), + ("comment.doc".into(), rgba(0xafabb1ff).into()), + ("text.literal".into(), rgba(0xf29c14ff).into()), + ("constant".into(), rgba(0x96df71ff).into()), + ("string.regex".into(), rgba(0xf29c14ff).into()), + ("emphasis.strong".into(), rgba(0x10a793ff).into()), + ("title".into(), rgba(0xf7f7f8ff).into()), + ("punctuation.delimiter".into(), rgba(0xd8d5dbff).into()), + ("link_uri".into(), rgba(0x96df71ff).into()), + ("boolean".into(), rgba(0x96df71ff).into()), + ("punctuation.list_marker".into(), rgba(0xd8d5dbff).into()), + ], + }, + status_bar: rgba(0x262933ff).into(), + title_bar: rgba(0x262933ff).into(), + toolbar: rgba(0x1e2025ff).into(), + tab_bar: rgba(0x21242bff).into(), + editor: rgba(0x1e2025ff).into(), + editor_subheader: rgba(0x21242bff).into(), + editor_active_line: rgba(0x21242bff).into(), + terminal: rgba(0x1e2025ff).into(), + image_fallback_background: rgba(0x262933ff).into(), + git_created: rgba(0x96df71ff).into(), + git_modified: rgba(0x10a793ff).into(), + git_deleted: rgba(0xf82871ff).into(), + git_conflict: rgba(0xfee56cff).into(), + git_ignored: rgba(0x6b6b73ff).into(), + git_renamed: rgba(0xfee56cff).into(), + players: [ + PlayerTheme { + cursor: rgba(0x10a793ff).into(), + selection: rgba(0x10a7933d).into(), + }, + PlayerTheme { + cursor: rgba(0x96df71ff).into(), + selection: rgba(0x96df713d).into(), + }, + PlayerTheme { + cursor: rgba(0xc74cecff).into(), + selection: rgba(0xc74cec3d).into(), + }, + PlayerTheme { + cursor: rgba(0xf29c14ff).into(), + selection: rgba(0xf29c143d).into(), + }, + PlayerTheme { + cursor: rgba(0x893ea6ff).into(), + selection: rgba(0x893ea63d).into(), + }, + PlayerTheme { + cursor: rgba(0x08e7c5ff).into(), + selection: rgba(0x08e7c53d).into(), + }, + PlayerTheme { + cursor: rgba(0xf82871ff).into(), + selection: rgba(0xf828713d).into(), + }, + PlayerTheme { + cursor: rgba(0xfee56cff).into(), + selection: rgba(0xfee56c3d).into(), + }, + ], + } +} diff --git a/crates/theme2/src/themes/atelier_cave_dark.rs b/crates/theme2/src/themes/atelier_cave_dark.rs new file mode 100644 index 0000000000..c5190f4e98 --- /dev/null +++ b/crates/theme2/src/themes/atelier_cave_dark.rs @@ -0,0 +1,136 @@ +use gpui2::rgba; + +use crate::{PlayerTheme, SyntaxTheme, Theme, ThemeMetadata}; + +pub fn atelier_cave_dark() -> Theme { + Theme { + metadata: ThemeMetadata { + name: "Atelier Cave Dark".into(), + is_light: false, + }, + transparent: rgba(0x00000000).into(), + mac_os_traffic_light_red: rgba(0xec695eff).into(), + mac_os_traffic_light_yellow: rgba(0xf4bf4eff).into(), + mac_os_traffic_light_green: rgba(0x61c553ff).into(), + border: rgba(0x56505eff).into(), + border_variant: rgba(0x56505eff).into(), + border_focused: rgba(0x222953ff).into(), + border_transparent: rgba(0x00000000).into(), + elevated_surface: rgba(0x3a353fff).into(), + surface: rgba(0x221f26ff).into(), + background: rgba(0x3a353fff).into(), + filled_element: rgba(0x3a353fff).into(), + filled_element_hover: rgba(0xffffff1e).into(), + filled_element_active: rgba(0xffffff28).into(), + filled_element_selected: rgba(0x161a35ff).into(), + filled_element_disabled: rgba(0x00000000).into(), + ghost_element: rgba(0x00000000).into(), + ghost_element_hover: rgba(0xffffff14).into(), + ghost_element_active: rgba(0xffffff1e).into(), + ghost_element_selected: rgba(0x161a35ff).into(), + ghost_element_disabled: rgba(0x00000000).into(), + text: rgba(0xefecf4ff).into(), + text_muted: rgba(0x898591ff).into(), + text_placeholder: rgba(0xbe4677ff).into(), + text_disabled: rgba(0x756f7eff).into(), + text_accent: rgba(0x566ddaff).into(), + icon_muted: rgba(0x898591ff).into(), + syntax: SyntaxTheme { + highlights: vec![ + ("comment.doc".into(), rgba(0x8b8792ff).into()), + ("tag".into(), rgba(0x566ddaff).into()), + ("link_text".into(), rgba(0xaa563bff).into()), + ("constructor".into(), rgba(0x566ddaff).into()), + ("punctuation".into(), rgba(0xe2dfe7ff).into()), + ("punctuation.special".into(), rgba(0xbf3fbfff).into()), + ("string.special.symbol".into(), rgba(0x299292ff).into()), + ("string.escape".into(), rgba(0x8b8792ff).into()), + ("emphasis".into(), rgba(0x566ddaff).into()), + ("type".into(), rgba(0xa06d3aff).into()), + ("punctuation.delimiter".into(), rgba(0x8b8792ff).into()), + ("variant".into(), rgba(0xa06d3aff).into()), + ("variable.special".into(), rgba(0x9559e7ff).into()), + ("text.literal".into(), rgba(0xaa563bff).into()), + ("punctuation.list_marker".into(), rgba(0xe2dfe7ff).into()), + ("comment".into(), rgba(0x655f6dff).into()), + ("function.method".into(), rgba(0x576cdbff).into()), + ("property".into(), rgba(0xbe4677ff).into()), + ("operator".into(), rgba(0x8b8792ff).into()), + ("emphasis.strong".into(), rgba(0x566ddaff).into()), + ("label".into(), rgba(0x566ddaff).into()), + ("enum".into(), rgba(0xaa563bff).into()), + ("number".into(), rgba(0xaa563bff).into()), + ("primary".into(), rgba(0xe2dfe7ff).into()), + ("keyword".into(), rgba(0x9559e7ff).into()), + ( + "function.special.definition".into(), + rgba(0xa06d3aff).into(), + ), + ("punctuation.bracket".into(), rgba(0x8b8792ff).into()), + ("constant".into(), rgba(0x2b9292ff).into()), + ("string.special".into(), rgba(0xbf3fbfff).into()), + ("title".into(), rgba(0xefecf4ff).into()), + ("preproc".into(), rgba(0xefecf4ff).into()), + ("link_uri".into(), rgba(0x2b9292ff).into()), + ("string".into(), rgba(0x299292ff).into()), + ("embedded".into(), rgba(0xefecf4ff).into()), + ("hint".into(), rgba(0x706897ff).into()), + ("boolean".into(), rgba(0x2b9292ff).into()), + ("variable".into(), rgba(0xe2dfe7ff).into()), + ("predictive".into(), rgba(0x615787ff).into()), + ("string.regex".into(), rgba(0x388bc6ff).into()), + ("function".into(), rgba(0x576cdbff).into()), + ("attribute".into(), rgba(0x566ddaff).into()), + ], + }, + status_bar: rgba(0x3a353fff).into(), + title_bar: rgba(0x3a353fff).into(), + toolbar: rgba(0x19171cff).into(), + tab_bar: rgba(0x221f26ff).into(), + editor: rgba(0x19171cff).into(), + editor_subheader: rgba(0x221f26ff).into(), + editor_active_line: rgba(0x221f26ff).into(), + terminal: rgba(0x19171cff).into(), + image_fallback_background: rgba(0x3a353fff).into(), + git_created: rgba(0x2b9292ff).into(), + git_modified: rgba(0x566ddaff).into(), + git_deleted: rgba(0xbe4677ff).into(), + git_conflict: rgba(0xa06d3aff).into(), + git_ignored: rgba(0x756f7eff).into(), + git_renamed: rgba(0xa06d3aff).into(), + players: [ + PlayerTheme { + cursor: rgba(0x566ddaff).into(), + selection: rgba(0x566dda3d).into(), + }, + PlayerTheme { + cursor: rgba(0x2b9292ff).into(), + selection: rgba(0x2b92923d).into(), + }, + PlayerTheme { + cursor: rgba(0xbf41bfff).into(), + selection: rgba(0xbf41bf3d).into(), + }, + PlayerTheme { + cursor: rgba(0xaa563bff).into(), + selection: rgba(0xaa563b3d).into(), + }, + PlayerTheme { + cursor: rgba(0x955ae6ff).into(), + selection: rgba(0x955ae63d).into(), + }, + PlayerTheme { + cursor: rgba(0x3a8bc6ff).into(), + selection: rgba(0x3a8bc63d).into(), + }, + PlayerTheme { + cursor: rgba(0xbe4677ff).into(), + selection: rgba(0xbe46773d).into(), + }, + PlayerTheme { + cursor: rgba(0xa06d3aff).into(), + selection: rgba(0xa06d3a3d).into(), + }, + ], + } +} diff --git a/crates/theme2/src/themes/atelier_cave_light.rs b/crates/theme2/src/themes/atelier_cave_light.rs new file mode 100644 index 0000000000..ae2e912f14 --- /dev/null +++ b/crates/theme2/src/themes/atelier_cave_light.rs @@ -0,0 +1,136 @@ +use gpui2::rgba; + +use crate::{PlayerTheme, SyntaxTheme, Theme, ThemeMetadata}; + +pub fn atelier_cave_light() -> Theme { + Theme { + metadata: ThemeMetadata { + name: "Atelier Cave Light".into(), + is_light: true, + }, + transparent: rgba(0x00000000).into(), + mac_os_traffic_light_red: rgba(0xec695eff).into(), + mac_os_traffic_light_yellow: rgba(0xf4bf4eff).into(), + mac_os_traffic_light_green: rgba(0x61c553ff).into(), + border: rgba(0x8f8b96ff).into(), + border_variant: rgba(0x8f8b96ff).into(), + border_focused: rgba(0xc8c7f2ff).into(), + border_transparent: rgba(0x00000000).into(), + elevated_surface: rgba(0xbfbcc5ff).into(), + surface: rgba(0xe6e3ebff).into(), + background: rgba(0xbfbcc5ff).into(), + filled_element: rgba(0xbfbcc5ff).into(), + filled_element_hover: rgba(0xffffff1e).into(), + filled_element_active: rgba(0xffffff28).into(), + filled_element_selected: rgba(0xe1e0f9ff).into(), + filled_element_disabled: rgba(0x00000000).into(), + ghost_element: rgba(0x00000000).into(), + ghost_element_hover: rgba(0xffffff14).into(), + ghost_element_active: rgba(0xffffff1e).into(), + ghost_element_selected: rgba(0xe1e0f9ff).into(), + ghost_element_disabled: rgba(0x00000000).into(), + text: rgba(0x19171cff).into(), + text_muted: rgba(0x5a5462ff).into(), + text_placeholder: rgba(0xbd4677ff).into(), + text_disabled: rgba(0x6e6876ff).into(), + text_accent: rgba(0x586cdaff).into(), + icon_muted: rgba(0x5a5462ff).into(), + syntax: SyntaxTheme { + highlights: vec![ + ("link_text".into(), rgba(0xaa573cff).into()), + ("string".into(), rgba(0x299292ff).into()), + ("emphasis".into(), rgba(0x586cdaff).into()), + ("label".into(), rgba(0x586cdaff).into()), + ("property".into(), rgba(0xbe4677ff).into()), + ("emphasis.strong".into(), rgba(0x586cdaff).into()), + ("constant".into(), rgba(0x2b9292ff).into()), + ( + "function.special.definition".into(), + rgba(0xa06d3aff).into(), + ), + ("embedded".into(), rgba(0x19171cff).into()), + ("punctuation.special".into(), rgba(0xbf3fbfff).into()), + ("function".into(), rgba(0x576cdbff).into()), + ("tag".into(), rgba(0x586cdaff).into()), + ("number".into(), rgba(0xaa563bff).into()), + ("primary".into(), rgba(0x26232aff).into()), + ("text.literal".into(), rgba(0xaa573cff).into()), + ("variant".into(), rgba(0xa06d3aff).into()), + ("type".into(), rgba(0xa06d3aff).into()), + ("punctuation".into(), rgba(0x26232aff).into()), + ("string.escape".into(), rgba(0x585260ff).into()), + ("keyword".into(), rgba(0x9559e7ff).into()), + ("title".into(), rgba(0x19171cff).into()), + ("constructor".into(), rgba(0x586cdaff).into()), + ("punctuation.list_marker".into(), rgba(0x26232aff).into()), + ("string.special".into(), rgba(0xbf3fbfff).into()), + ("operator".into(), rgba(0x585260ff).into()), + ("function.method".into(), rgba(0x576cdbff).into()), + ("link_uri".into(), rgba(0x2b9292ff).into()), + ("variable.special".into(), rgba(0x9559e7ff).into()), + ("hint".into(), rgba(0x776d9dff).into()), + ("punctuation.bracket".into(), rgba(0x585260ff).into()), + ("string.special.symbol".into(), rgba(0x299292ff).into()), + ("predictive".into(), rgba(0x887fafff).into()), + ("attribute".into(), rgba(0x586cdaff).into()), + ("enum".into(), rgba(0xaa573cff).into()), + ("preproc".into(), rgba(0x19171cff).into()), + ("boolean".into(), rgba(0x2b9292ff).into()), + ("variable".into(), rgba(0x26232aff).into()), + ("comment.doc".into(), rgba(0x585260ff).into()), + ("string.regex".into(), rgba(0x388bc6ff).into()), + ("punctuation.delimiter".into(), rgba(0x585260ff).into()), + ("comment".into(), rgba(0x7d7787ff).into()), + ], + }, + status_bar: rgba(0xbfbcc5ff).into(), + title_bar: rgba(0xbfbcc5ff).into(), + toolbar: rgba(0xefecf4ff).into(), + tab_bar: rgba(0xe6e3ebff).into(), + editor: rgba(0xefecf4ff).into(), + editor_subheader: rgba(0xe6e3ebff).into(), + editor_active_line: rgba(0xe6e3ebff).into(), + terminal: rgba(0xefecf4ff).into(), + image_fallback_background: rgba(0xbfbcc5ff).into(), + git_created: rgba(0x2b9292ff).into(), + git_modified: rgba(0x586cdaff).into(), + git_deleted: rgba(0xbd4677ff).into(), + git_conflict: rgba(0xa06e3bff).into(), + git_ignored: rgba(0x6e6876ff).into(), + git_renamed: rgba(0xa06e3bff).into(), + players: [ + PlayerTheme { + cursor: rgba(0x586cdaff).into(), + selection: rgba(0x586cda3d).into(), + }, + PlayerTheme { + cursor: rgba(0x2b9292ff).into(), + selection: rgba(0x2b92923d).into(), + }, + PlayerTheme { + cursor: rgba(0xbf41bfff).into(), + selection: rgba(0xbf41bf3d).into(), + }, + PlayerTheme { + cursor: rgba(0xaa573cff).into(), + selection: rgba(0xaa573c3d).into(), + }, + PlayerTheme { + cursor: rgba(0x955ae6ff).into(), + selection: rgba(0x955ae63d).into(), + }, + PlayerTheme { + cursor: rgba(0x3a8bc6ff).into(), + selection: rgba(0x3a8bc63d).into(), + }, + PlayerTheme { + cursor: rgba(0xbd4677ff).into(), + selection: rgba(0xbd46773d).into(), + }, + PlayerTheme { + cursor: rgba(0xa06e3bff).into(), + selection: rgba(0xa06e3b3d).into(), + }, + ], + } +} diff --git a/crates/theme2/src/themes/atelier_dune_dark.rs b/crates/theme2/src/themes/atelier_dune_dark.rs new file mode 100644 index 0000000000..03d0c5eea0 --- /dev/null +++ b/crates/theme2/src/themes/atelier_dune_dark.rs @@ -0,0 +1,136 @@ +use gpui2::rgba; + +use crate::{PlayerTheme, SyntaxTheme, Theme, ThemeMetadata}; + +pub fn atelier_dune_dark() -> Theme { + Theme { + metadata: ThemeMetadata { + name: "Atelier Dune Dark".into(), + is_light: false, + }, + transparent: rgba(0x00000000).into(), + mac_os_traffic_light_red: rgba(0xec695eff).into(), + mac_os_traffic_light_yellow: rgba(0xf4bf4eff).into(), + mac_os_traffic_light_green: rgba(0x61c553ff).into(), + border: rgba(0x6c695cff).into(), + border_variant: rgba(0x6c695cff).into(), + border_focused: rgba(0x262f56ff).into(), + border_transparent: rgba(0x00000000).into(), + elevated_surface: rgba(0x45433bff).into(), + surface: rgba(0x262622ff).into(), + background: rgba(0x45433bff).into(), + filled_element: rgba(0x45433bff).into(), + filled_element_hover: rgba(0xffffff1e).into(), + filled_element_active: rgba(0xffffff28).into(), + filled_element_selected: rgba(0x171e38ff).into(), + filled_element_disabled: rgba(0x00000000).into(), + ghost_element: rgba(0x00000000).into(), + ghost_element_hover: rgba(0xffffff14).into(), + ghost_element_active: rgba(0xffffff1e).into(), + ghost_element_selected: rgba(0x171e38ff).into(), + ghost_element_disabled: rgba(0x00000000).into(), + text: rgba(0xfefbecff).into(), + text_muted: rgba(0xa4a08bff).into(), + text_placeholder: rgba(0xd73837ff).into(), + text_disabled: rgba(0x8f8b77ff).into(), + text_accent: rgba(0x6684e0ff).into(), + icon_muted: rgba(0xa4a08bff).into(), + syntax: SyntaxTheme { + highlights: vec![ + ("constructor".into(), rgba(0x6684e0ff).into()), + ("punctuation".into(), rgba(0xe8e4cfff).into()), + ("punctuation.delimiter".into(), rgba(0xa6a28cff).into()), + ("string.special".into(), rgba(0xd43451ff).into()), + ("string.escape".into(), rgba(0xa6a28cff).into()), + ("comment".into(), rgba(0x7d7a68ff).into()), + ("enum".into(), rgba(0xb65611ff).into()), + ("variable.special".into(), rgba(0xb854d4ff).into()), + ("primary".into(), rgba(0xe8e4cfff).into()), + ("comment.doc".into(), rgba(0xa6a28cff).into()), + ("label".into(), rgba(0x6684e0ff).into()), + ("operator".into(), rgba(0xa6a28cff).into()), + ("string".into(), rgba(0x5fac38ff).into()), + ("variant".into(), rgba(0xae9512ff).into()), + ("variable".into(), rgba(0xe8e4cfff).into()), + ("function.method".into(), rgba(0x6583e1ff).into()), + ( + "function.special.definition".into(), + rgba(0xae9512ff).into(), + ), + ("string.regex".into(), rgba(0x1ead82ff).into()), + ("emphasis.strong".into(), rgba(0x6684e0ff).into()), + ("punctuation.special".into(), rgba(0xd43451ff).into()), + ("punctuation.bracket".into(), rgba(0xa6a28cff).into()), + ("link_text".into(), rgba(0xb65611ff).into()), + ("link_uri".into(), rgba(0x5fac39ff).into()), + ("boolean".into(), rgba(0x5fac39ff).into()), + ("hint".into(), rgba(0xb17272ff).into()), + ("tag".into(), rgba(0x6684e0ff).into()), + ("function".into(), rgba(0x6583e1ff).into()), + ("title".into(), rgba(0xfefbecff).into()), + ("property".into(), rgba(0xd73737ff).into()), + ("type".into(), rgba(0xae9512ff).into()), + ("constant".into(), rgba(0x5fac39ff).into()), + ("attribute".into(), rgba(0x6684e0ff).into()), + ("predictive".into(), rgba(0x9c6262ff).into()), + ("string.special.symbol".into(), rgba(0x5fac38ff).into()), + ("punctuation.list_marker".into(), rgba(0xe8e4cfff).into()), + ("emphasis".into(), rgba(0x6684e0ff).into()), + ("keyword".into(), rgba(0xb854d4ff).into()), + ("text.literal".into(), rgba(0xb65611ff).into()), + ("number".into(), rgba(0xb65610ff).into()), + ("preproc".into(), rgba(0xfefbecff).into()), + ("embedded".into(), rgba(0xfefbecff).into()), + ], + }, + status_bar: rgba(0x45433bff).into(), + title_bar: rgba(0x45433bff).into(), + toolbar: rgba(0x20201dff).into(), + tab_bar: rgba(0x262622ff).into(), + editor: rgba(0x20201dff).into(), + editor_subheader: rgba(0x262622ff).into(), + editor_active_line: rgba(0x262622ff).into(), + terminal: rgba(0x20201dff).into(), + image_fallback_background: rgba(0x45433bff).into(), + git_created: rgba(0x5fac39ff).into(), + git_modified: rgba(0x6684e0ff).into(), + git_deleted: rgba(0xd73837ff).into(), + git_conflict: rgba(0xae9414ff).into(), + git_ignored: rgba(0x8f8b77ff).into(), + git_renamed: rgba(0xae9414ff).into(), + players: [ + PlayerTheme { + cursor: rgba(0x6684e0ff).into(), + selection: rgba(0x6684e03d).into(), + }, + PlayerTheme { + cursor: rgba(0x5fac39ff).into(), + selection: rgba(0x5fac393d).into(), + }, + PlayerTheme { + cursor: rgba(0xd43651ff).into(), + selection: rgba(0xd436513d).into(), + }, + PlayerTheme { + cursor: rgba(0xb65611ff).into(), + selection: rgba(0xb656113d).into(), + }, + PlayerTheme { + cursor: rgba(0xb854d3ff).into(), + selection: rgba(0xb854d33d).into(), + }, + PlayerTheme { + cursor: rgba(0x20ad83ff).into(), + selection: rgba(0x20ad833d).into(), + }, + PlayerTheme { + cursor: rgba(0xd73837ff).into(), + selection: rgba(0xd738373d).into(), + }, + PlayerTheme { + cursor: rgba(0xae9414ff).into(), + selection: rgba(0xae94143d).into(), + }, + ], + } +} diff --git a/crates/theme2/src/themes/atelier_dune_light.rs b/crates/theme2/src/themes/atelier_dune_light.rs new file mode 100644 index 0000000000..1d0f944916 --- /dev/null +++ b/crates/theme2/src/themes/atelier_dune_light.rs @@ -0,0 +1,136 @@ +use gpui2::rgba; + +use crate::{PlayerTheme, SyntaxTheme, Theme, ThemeMetadata}; + +pub fn atelier_dune_light() -> Theme { + Theme { + metadata: ThemeMetadata { + name: "Atelier Dune Light".into(), + is_light: true, + }, + transparent: rgba(0x00000000).into(), + mac_os_traffic_light_red: rgba(0xec695eff).into(), + mac_os_traffic_light_yellow: rgba(0xf4bf4eff).into(), + mac_os_traffic_light_green: rgba(0x61c553ff).into(), + border: rgba(0xa8a48eff).into(), + border_variant: rgba(0xa8a48eff).into(), + border_focused: rgba(0xcdd1f5ff).into(), + border_transparent: rgba(0x00000000).into(), + elevated_surface: rgba(0xcecab4ff).into(), + surface: rgba(0xeeebd7ff).into(), + background: rgba(0xcecab4ff).into(), + filled_element: rgba(0xcecab4ff).into(), + filled_element_hover: rgba(0xffffff1e).into(), + filled_element_active: rgba(0xffffff28).into(), + filled_element_selected: rgba(0xe3e5faff).into(), + filled_element_disabled: rgba(0x00000000).into(), + ghost_element: rgba(0x00000000).into(), + ghost_element_hover: rgba(0xffffff14).into(), + ghost_element_active: rgba(0xffffff1e).into(), + ghost_element_selected: rgba(0xe3e5faff).into(), + ghost_element_disabled: rgba(0x00000000).into(), + text: rgba(0x20201dff).into(), + text_muted: rgba(0x706d5fff).into(), + text_placeholder: rgba(0xd73737ff).into(), + text_disabled: rgba(0x878471ff).into(), + text_accent: rgba(0x6684dfff).into(), + icon_muted: rgba(0x706d5fff).into(), + syntax: SyntaxTheme { + highlights: vec![ + ("primary".into(), rgba(0x292824ff).into()), + ("comment".into(), rgba(0x999580ff).into()), + ("type".into(), rgba(0xae9512ff).into()), + ("variant".into(), rgba(0xae9512ff).into()), + ("label".into(), rgba(0x6684dfff).into()), + ("function.method".into(), rgba(0x6583e1ff).into()), + ("variable.special".into(), rgba(0xb854d4ff).into()), + ("string.regex".into(), rgba(0x1ead82ff).into()), + ("property".into(), rgba(0xd73737ff).into()), + ("keyword".into(), rgba(0xb854d4ff).into()), + ("number".into(), rgba(0xb65610ff).into()), + ("punctuation.list_marker".into(), rgba(0x292824ff).into()), + ( + "function.special.definition".into(), + rgba(0xae9512ff).into(), + ), + ("punctuation.special".into(), rgba(0xd43451ff).into()), + ("punctuation".into(), rgba(0x292824ff).into()), + ("punctuation.delimiter".into(), rgba(0x6e6b5eff).into()), + ("tag".into(), rgba(0x6684dfff).into()), + ("link_text".into(), rgba(0xb65712ff).into()), + ("boolean".into(), rgba(0x61ac39ff).into()), + ("hint".into(), rgba(0xb37979ff).into()), + ("operator".into(), rgba(0x6e6b5eff).into()), + ("constant".into(), rgba(0x61ac39ff).into()), + ("function".into(), rgba(0x6583e1ff).into()), + ("text.literal".into(), rgba(0xb65712ff).into()), + ("string.special.symbol".into(), rgba(0x5fac38ff).into()), + ("attribute".into(), rgba(0x6684dfff).into()), + ("emphasis".into(), rgba(0x6684dfff).into()), + ("preproc".into(), rgba(0x20201dff).into()), + ("comment.doc".into(), rgba(0x6e6b5eff).into()), + ("punctuation.bracket".into(), rgba(0x6e6b5eff).into()), + ("string".into(), rgba(0x5fac38ff).into()), + ("enum".into(), rgba(0xb65712ff).into()), + ("variable".into(), rgba(0x292824ff).into()), + ("string.special".into(), rgba(0xd43451ff).into()), + ("embedded".into(), rgba(0x20201dff).into()), + ("emphasis.strong".into(), rgba(0x6684dfff).into()), + ("predictive".into(), rgba(0xc88a8aff).into()), + ("title".into(), rgba(0x20201dff).into()), + ("constructor".into(), rgba(0x6684dfff).into()), + ("link_uri".into(), rgba(0x61ac39ff).into()), + ("string.escape".into(), rgba(0x6e6b5eff).into()), + ], + }, + status_bar: rgba(0xcecab4ff).into(), + title_bar: rgba(0xcecab4ff).into(), + toolbar: rgba(0xfefbecff).into(), + tab_bar: rgba(0xeeebd7ff).into(), + editor: rgba(0xfefbecff).into(), + editor_subheader: rgba(0xeeebd7ff).into(), + editor_active_line: rgba(0xeeebd7ff).into(), + terminal: rgba(0xfefbecff).into(), + image_fallback_background: rgba(0xcecab4ff).into(), + git_created: rgba(0x61ac39ff).into(), + git_modified: rgba(0x6684dfff).into(), + git_deleted: rgba(0xd73737ff).into(), + git_conflict: rgba(0xae9414ff).into(), + git_ignored: rgba(0x878471ff).into(), + git_renamed: rgba(0xae9414ff).into(), + players: [ + PlayerTheme { + cursor: rgba(0x6684dfff).into(), + selection: rgba(0x6684df3d).into(), + }, + PlayerTheme { + cursor: rgba(0x61ac39ff).into(), + selection: rgba(0x61ac393d).into(), + }, + PlayerTheme { + cursor: rgba(0xd43652ff).into(), + selection: rgba(0xd436523d).into(), + }, + PlayerTheme { + cursor: rgba(0xb65712ff).into(), + selection: rgba(0xb657123d).into(), + }, + PlayerTheme { + cursor: rgba(0xb755d3ff).into(), + selection: rgba(0xb755d33d).into(), + }, + PlayerTheme { + cursor: rgba(0x21ad82ff).into(), + selection: rgba(0x21ad823d).into(), + }, + PlayerTheme { + cursor: rgba(0xd73737ff).into(), + selection: rgba(0xd737373d).into(), + }, + PlayerTheme { + cursor: rgba(0xae9414ff).into(), + selection: rgba(0xae94143d).into(), + }, + ], + } +} diff --git a/crates/theme2/src/themes/atelier_estuary_dark.rs b/crates/theme2/src/themes/atelier_estuary_dark.rs new file mode 100644 index 0000000000..ad5c9fbc1e --- /dev/null +++ b/crates/theme2/src/themes/atelier_estuary_dark.rs @@ -0,0 +1,136 @@ +use gpui2::rgba; + +use crate::{PlayerTheme, SyntaxTheme, Theme, ThemeMetadata}; + +pub fn atelier_estuary_dark() -> Theme { + Theme { + metadata: ThemeMetadata { + name: "Atelier Estuary Dark".into(), + is_light: false, + }, + transparent: rgba(0x00000000).into(), + mac_os_traffic_light_red: rgba(0xec695eff).into(), + mac_os_traffic_light_yellow: rgba(0xf4bf4eff).into(), + mac_os_traffic_light_green: rgba(0x61c553ff).into(), + border: rgba(0x5d5c4cff).into(), + border_variant: rgba(0x5d5c4cff).into(), + border_focused: rgba(0x1c3927ff).into(), + border_transparent: rgba(0x00000000).into(), + elevated_surface: rgba(0x424136ff).into(), + surface: rgba(0x2c2b23ff).into(), + background: rgba(0x424136ff).into(), + filled_element: rgba(0x424136ff).into(), + filled_element_hover: rgba(0xffffff1e).into(), + filled_element_active: rgba(0xffffff28).into(), + filled_element_selected: rgba(0x142319ff).into(), + filled_element_disabled: rgba(0x00000000).into(), + ghost_element: rgba(0x00000000).into(), + ghost_element_hover: rgba(0xffffff14).into(), + ghost_element_active: rgba(0xffffff1e).into(), + ghost_element_selected: rgba(0x142319ff).into(), + ghost_element_disabled: rgba(0x00000000).into(), + text: rgba(0xf4f3ecff).into(), + text_muted: rgba(0x91907fff).into(), + text_placeholder: rgba(0xba6136ff).into(), + text_disabled: rgba(0x7d7c6aff).into(), + text_accent: rgba(0x36a165ff).into(), + icon_muted: rgba(0x91907fff).into(), + syntax: SyntaxTheme { + highlights: vec![ + ("string.special.symbol".into(), rgba(0x7c9725ff).into()), + ("comment".into(), rgba(0x6c6b5aff).into()), + ("operator".into(), rgba(0x929181ff).into()), + ("punctuation.delimiter".into(), rgba(0x929181ff).into()), + ("keyword".into(), rgba(0x5f9182ff).into()), + ("punctuation.special".into(), rgba(0x9d6b7bff).into()), + ("preproc".into(), rgba(0xf4f3ecff).into()), + ("title".into(), rgba(0xf4f3ecff).into()), + ("string.escape".into(), rgba(0x929181ff).into()), + ("boolean".into(), rgba(0x7d9726ff).into()), + ("punctuation.bracket".into(), rgba(0x929181ff).into()), + ("emphasis.strong".into(), rgba(0x36a165ff).into()), + ("string".into(), rgba(0x7c9725ff).into()), + ("constant".into(), rgba(0x7d9726ff).into()), + ("link_text".into(), rgba(0xae7214ff).into()), + ("tag".into(), rgba(0x36a165ff).into()), + ("hint".into(), rgba(0x6f815aff).into()), + ("punctuation".into(), rgba(0xe7e6dfff).into()), + ("string.regex".into(), rgba(0x5a9d47ff).into()), + ("variant".into(), rgba(0xa5980cff).into()), + ("type".into(), rgba(0xa5980cff).into()), + ("attribute".into(), rgba(0x36a165ff).into()), + ("emphasis".into(), rgba(0x36a165ff).into()), + ("enum".into(), rgba(0xae7214ff).into()), + ("number".into(), rgba(0xae7312ff).into()), + ("property".into(), rgba(0xba6135ff).into()), + ("predictive".into(), rgba(0x5f724cff).into()), + ( + "function.special.definition".into(), + rgba(0xa5980cff).into(), + ), + ("link_uri".into(), rgba(0x7d9726ff).into()), + ("variable.special".into(), rgba(0x5f9182ff).into()), + ("text.literal".into(), rgba(0xae7214ff).into()), + ("label".into(), rgba(0x36a165ff).into()), + ("primary".into(), rgba(0xe7e6dfff).into()), + ("variable".into(), rgba(0xe7e6dfff).into()), + ("embedded".into(), rgba(0xf4f3ecff).into()), + ("function.method".into(), rgba(0x35a166ff).into()), + ("comment.doc".into(), rgba(0x929181ff).into()), + ("string.special".into(), rgba(0x9d6b7bff).into()), + ("constructor".into(), rgba(0x36a165ff).into()), + ("punctuation.list_marker".into(), rgba(0xe7e6dfff).into()), + ("function".into(), rgba(0x35a166ff).into()), + ], + }, + status_bar: rgba(0x424136ff).into(), + title_bar: rgba(0x424136ff).into(), + toolbar: rgba(0x22221bff).into(), + tab_bar: rgba(0x2c2b23ff).into(), + editor: rgba(0x22221bff).into(), + editor_subheader: rgba(0x2c2b23ff).into(), + editor_active_line: rgba(0x2c2b23ff).into(), + terminal: rgba(0x22221bff).into(), + image_fallback_background: rgba(0x424136ff).into(), + git_created: rgba(0x7d9726ff).into(), + git_modified: rgba(0x36a165ff).into(), + git_deleted: rgba(0xba6136ff).into(), + git_conflict: rgba(0xa5980fff).into(), + git_ignored: rgba(0x7d7c6aff).into(), + git_renamed: rgba(0xa5980fff).into(), + players: [ + PlayerTheme { + cursor: rgba(0x36a165ff).into(), + selection: rgba(0x36a1653d).into(), + }, + PlayerTheme { + cursor: rgba(0x7d9726ff).into(), + selection: rgba(0x7d97263d).into(), + }, + PlayerTheme { + cursor: rgba(0x9d6b7bff).into(), + selection: rgba(0x9d6b7b3d).into(), + }, + PlayerTheme { + cursor: rgba(0xae7214ff).into(), + selection: rgba(0xae72143d).into(), + }, + PlayerTheme { + cursor: rgba(0x5f9182ff).into(), + selection: rgba(0x5f91823d).into(), + }, + PlayerTheme { + cursor: rgba(0x5a9d47ff).into(), + selection: rgba(0x5a9d473d).into(), + }, + PlayerTheme { + cursor: rgba(0xba6136ff).into(), + selection: rgba(0xba61363d).into(), + }, + PlayerTheme { + cursor: rgba(0xa5980fff).into(), + selection: rgba(0xa5980f3d).into(), + }, + ], + } +} diff --git a/crates/theme2/src/themes/atelier_estuary_light.rs b/crates/theme2/src/themes/atelier_estuary_light.rs new file mode 100644 index 0000000000..91eaa88fab --- /dev/null +++ b/crates/theme2/src/themes/atelier_estuary_light.rs @@ -0,0 +1,136 @@ +use gpui2::rgba; + +use crate::{PlayerTheme, SyntaxTheme, Theme, ThemeMetadata}; + +pub fn atelier_estuary_light() -> Theme { + Theme { + metadata: ThemeMetadata { + name: "Atelier Estuary Light".into(), + is_light: true, + }, + transparent: rgba(0x00000000).into(), + mac_os_traffic_light_red: rgba(0xec695eff).into(), + mac_os_traffic_light_yellow: rgba(0xf4bf4eff).into(), + mac_os_traffic_light_green: rgba(0x61c553ff).into(), + border: rgba(0x969585ff).into(), + border_variant: rgba(0x969585ff).into(), + border_focused: rgba(0xbbddc6ff).into(), + border_transparent: rgba(0x00000000).into(), + elevated_surface: rgba(0xc5c4b9ff).into(), + surface: rgba(0xebeae3ff).into(), + background: rgba(0xc5c4b9ff).into(), + filled_element: rgba(0xc5c4b9ff).into(), + filled_element_hover: rgba(0xffffff1e).into(), + filled_element_active: rgba(0xffffff28).into(), + filled_element_selected: rgba(0xd9ecdfff).into(), + filled_element_disabled: rgba(0x00000000).into(), + ghost_element: rgba(0x00000000).into(), + ghost_element_hover: rgba(0xffffff14).into(), + ghost_element_active: rgba(0xffffff1e).into(), + ghost_element_selected: rgba(0xd9ecdfff).into(), + ghost_element_disabled: rgba(0x00000000).into(), + text: rgba(0x22221bff).into(), + text_muted: rgba(0x61604fff).into(), + text_placeholder: rgba(0xba6336ff).into(), + text_disabled: rgba(0x767463ff).into(), + text_accent: rgba(0x37a165ff).into(), + icon_muted: rgba(0x61604fff).into(), + syntax: SyntaxTheme { + highlights: vec![ + ("string.special".into(), rgba(0x9d6b7bff).into()), + ("link_text".into(), rgba(0xae7214ff).into()), + ("emphasis.strong".into(), rgba(0x37a165ff).into()), + ("tag".into(), rgba(0x37a165ff).into()), + ("primary".into(), rgba(0x302f27ff).into()), + ("emphasis".into(), rgba(0x37a165ff).into()), + ("hint".into(), rgba(0x758961ff).into()), + ("title".into(), rgba(0x22221bff).into()), + ("string.regex".into(), rgba(0x5a9d47ff).into()), + ("attribute".into(), rgba(0x37a165ff).into()), + ("string.escape".into(), rgba(0x5f5e4eff).into()), + ("embedded".into(), rgba(0x22221bff).into()), + ("punctuation.bracket".into(), rgba(0x5f5e4eff).into()), + ( + "function.special.definition".into(), + rgba(0xa5980cff).into(), + ), + ("operator".into(), rgba(0x5f5e4eff).into()), + ("constant".into(), rgba(0x7c9728ff).into()), + ("comment.doc".into(), rgba(0x5f5e4eff).into()), + ("label".into(), rgba(0x37a165ff).into()), + ("variable".into(), rgba(0x302f27ff).into()), + ("punctuation".into(), rgba(0x302f27ff).into()), + ("punctuation.delimiter".into(), rgba(0x5f5e4eff).into()), + ("comment".into(), rgba(0x878573ff).into()), + ("punctuation.special".into(), rgba(0x9d6b7bff).into()), + ("string.special.symbol".into(), rgba(0x7c9725ff).into()), + ("enum".into(), rgba(0xae7214ff).into()), + ("variable.special".into(), rgba(0x5f9182ff).into()), + ("link_uri".into(), rgba(0x7c9728ff).into()), + ("punctuation.list_marker".into(), rgba(0x302f27ff).into()), + ("number".into(), rgba(0xae7312ff).into()), + ("function".into(), rgba(0x35a166ff).into()), + ("text.literal".into(), rgba(0xae7214ff).into()), + ("boolean".into(), rgba(0x7c9728ff).into()), + ("predictive".into(), rgba(0x879a72ff).into()), + ("type".into(), rgba(0xa5980cff).into()), + ("constructor".into(), rgba(0x37a165ff).into()), + ("property".into(), rgba(0xba6135ff).into()), + ("keyword".into(), rgba(0x5f9182ff).into()), + ("function.method".into(), rgba(0x35a166ff).into()), + ("variant".into(), rgba(0xa5980cff).into()), + ("string".into(), rgba(0x7c9725ff).into()), + ("preproc".into(), rgba(0x22221bff).into()), + ], + }, + status_bar: rgba(0xc5c4b9ff).into(), + title_bar: rgba(0xc5c4b9ff).into(), + toolbar: rgba(0xf4f3ecff).into(), + tab_bar: rgba(0xebeae3ff).into(), + editor: rgba(0xf4f3ecff).into(), + editor_subheader: rgba(0xebeae3ff).into(), + editor_active_line: rgba(0xebeae3ff).into(), + terminal: rgba(0xf4f3ecff).into(), + image_fallback_background: rgba(0xc5c4b9ff).into(), + git_created: rgba(0x7c9728ff).into(), + git_modified: rgba(0x37a165ff).into(), + git_deleted: rgba(0xba6336ff).into(), + git_conflict: rgba(0xa5980fff).into(), + git_ignored: rgba(0x767463ff).into(), + git_renamed: rgba(0xa5980fff).into(), + players: [ + PlayerTheme { + cursor: rgba(0x37a165ff).into(), + selection: rgba(0x37a1653d).into(), + }, + PlayerTheme { + cursor: rgba(0x7c9728ff).into(), + selection: rgba(0x7c97283d).into(), + }, + PlayerTheme { + cursor: rgba(0x9d6b7bff).into(), + selection: rgba(0x9d6b7b3d).into(), + }, + PlayerTheme { + cursor: rgba(0xae7214ff).into(), + selection: rgba(0xae72143d).into(), + }, + PlayerTheme { + cursor: rgba(0x5f9182ff).into(), + selection: rgba(0x5f91823d).into(), + }, + PlayerTheme { + cursor: rgba(0x5c9d49ff).into(), + selection: rgba(0x5c9d493d).into(), + }, + PlayerTheme { + cursor: rgba(0xba6336ff).into(), + selection: rgba(0xba63363d).into(), + }, + PlayerTheme { + cursor: rgba(0xa5980fff).into(), + selection: rgba(0xa5980f3d).into(), + }, + ], + } +} diff --git a/crates/theme2/src/themes/atelier_forest_dark.rs b/crates/theme2/src/themes/atelier_forest_dark.rs new file mode 100644 index 0000000000..83228e671f --- /dev/null +++ b/crates/theme2/src/themes/atelier_forest_dark.rs @@ -0,0 +1,136 @@ +use gpui2::rgba; + +use crate::{PlayerTheme, SyntaxTheme, Theme, ThemeMetadata}; + +pub fn atelier_forest_dark() -> Theme { + Theme { + metadata: ThemeMetadata { + name: "Atelier Forest Dark".into(), + is_light: false, + }, + transparent: rgba(0x00000000).into(), + mac_os_traffic_light_red: rgba(0xec695eff).into(), + mac_os_traffic_light_yellow: rgba(0xf4bf4eff).into(), + mac_os_traffic_light_green: rgba(0x61c553ff).into(), + border: rgba(0x665f5cff).into(), + border_variant: rgba(0x665f5cff).into(), + border_focused: rgba(0x182d5bff).into(), + border_transparent: rgba(0x00000000).into(), + elevated_surface: rgba(0x443c39ff).into(), + surface: rgba(0x27211eff).into(), + background: rgba(0x443c39ff).into(), + filled_element: rgba(0x443c39ff).into(), + filled_element_hover: rgba(0xffffff1e).into(), + filled_element_active: rgba(0xffffff28).into(), + filled_element_selected: rgba(0x0f1c3dff).into(), + filled_element_disabled: rgba(0x00000000).into(), + ghost_element: rgba(0x00000000).into(), + ghost_element_hover: rgba(0xffffff14).into(), + ghost_element_active: rgba(0xffffff1e).into(), + ghost_element_selected: rgba(0x0f1c3dff).into(), + ghost_element_disabled: rgba(0x00000000).into(), + text: rgba(0xf0eeedff).into(), + text_muted: rgba(0xa79f9dff).into(), + text_placeholder: rgba(0xf22c3fff).into(), + text_disabled: rgba(0x8e8683ff).into(), + text_accent: rgba(0x407ee6ff).into(), + icon_muted: rgba(0xa79f9dff).into(), + syntax: SyntaxTheme { + highlights: vec![ + ("link_uri".into(), rgba(0x7a9726ff).into()), + ("punctuation.list_marker".into(), rgba(0xe6e2e0ff).into()), + ("type".into(), rgba(0xc38417ff).into()), + ("punctuation.bracket".into(), rgba(0xa8a19fff).into()), + ("punctuation".into(), rgba(0xe6e2e0ff).into()), + ("preproc".into(), rgba(0xf0eeedff).into()), + ("punctuation.special".into(), rgba(0xc33ff3ff).into()), + ("variable.special".into(), rgba(0x6666eaff).into()), + ("tag".into(), rgba(0x407ee6ff).into()), + ("constructor".into(), rgba(0x407ee6ff).into()), + ("title".into(), rgba(0xf0eeedff).into()), + ("hint".into(), rgba(0xa77087ff).into()), + ("constant".into(), rgba(0x7a9726ff).into()), + ("number".into(), rgba(0xdf521fff).into()), + ("emphasis.strong".into(), rgba(0x407ee6ff).into()), + ("boolean".into(), rgba(0x7a9726ff).into()), + ("comment".into(), rgba(0x766e6bff).into()), + ("string.special".into(), rgba(0xc33ff3ff).into()), + ("text.literal".into(), rgba(0xdf5321ff).into()), + ("string.regex".into(), rgba(0x3c96b8ff).into()), + ("enum".into(), rgba(0xdf5321ff).into()), + ("operator".into(), rgba(0xa8a19fff).into()), + ("embedded".into(), rgba(0xf0eeedff).into()), + ("string.special.symbol".into(), rgba(0x7a9725ff).into()), + ("predictive".into(), rgba(0x8f5b70ff).into()), + ("comment.doc".into(), rgba(0xa8a19fff).into()), + ("variant".into(), rgba(0xc38417ff).into()), + ("label".into(), rgba(0x407ee6ff).into()), + ("property".into(), rgba(0xf22c40ff).into()), + ("keyword".into(), rgba(0x6666eaff).into()), + ("function".into(), rgba(0x3f7ee7ff).into()), + ("string.escape".into(), rgba(0xa8a19fff).into()), + ("string".into(), rgba(0x7a9725ff).into()), + ("primary".into(), rgba(0xe6e2e0ff).into()), + ("function.method".into(), rgba(0x3f7ee7ff).into()), + ("link_text".into(), rgba(0xdf5321ff).into()), + ("attribute".into(), rgba(0x407ee6ff).into()), + ("emphasis".into(), rgba(0x407ee6ff).into()), + ( + "function.special.definition".into(), + rgba(0xc38417ff).into(), + ), + ("variable".into(), rgba(0xe6e2e0ff).into()), + ("punctuation.delimiter".into(), rgba(0xa8a19fff).into()), + ], + }, + status_bar: rgba(0x443c39ff).into(), + title_bar: rgba(0x443c39ff).into(), + toolbar: rgba(0x1b1918ff).into(), + tab_bar: rgba(0x27211eff).into(), + editor: rgba(0x1b1918ff).into(), + editor_subheader: rgba(0x27211eff).into(), + editor_active_line: rgba(0x27211eff).into(), + terminal: rgba(0x1b1918ff).into(), + image_fallback_background: rgba(0x443c39ff).into(), + git_created: rgba(0x7a9726ff).into(), + git_modified: rgba(0x407ee6ff).into(), + git_deleted: rgba(0xf22c3fff).into(), + git_conflict: rgba(0xc38418ff).into(), + git_ignored: rgba(0x8e8683ff).into(), + git_renamed: rgba(0xc38418ff).into(), + players: [ + PlayerTheme { + cursor: rgba(0x407ee6ff).into(), + selection: rgba(0x407ee63d).into(), + }, + PlayerTheme { + cursor: rgba(0x7a9726ff).into(), + selection: rgba(0x7a97263d).into(), + }, + PlayerTheme { + cursor: rgba(0xc340f2ff).into(), + selection: rgba(0xc340f23d).into(), + }, + PlayerTheme { + cursor: rgba(0xdf5321ff).into(), + selection: rgba(0xdf53213d).into(), + }, + PlayerTheme { + cursor: rgba(0x6565e9ff).into(), + selection: rgba(0x6565e93d).into(), + }, + PlayerTheme { + cursor: rgba(0x3d97b8ff).into(), + selection: rgba(0x3d97b83d).into(), + }, + PlayerTheme { + cursor: rgba(0xf22c3fff).into(), + selection: rgba(0xf22c3f3d).into(), + }, + PlayerTheme { + cursor: rgba(0xc38418ff).into(), + selection: rgba(0xc384183d).into(), + }, + ], + } +} diff --git a/crates/theme2/src/themes/atelier_forest_light.rs b/crates/theme2/src/themes/atelier_forest_light.rs new file mode 100644 index 0000000000..882d5c2fcb --- /dev/null +++ b/crates/theme2/src/themes/atelier_forest_light.rs @@ -0,0 +1,136 @@ +use gpui2::rgba; + +use crate::{PlayerTheme, SyntaxTheme, Theme, ThemeMetadata}; + +pub fn atelier_forest_light() -> Theme { + Theme { + metadata: ThemeMetadata { + name: "Atelier Forest Light".into(), + is_light: true, + }, + transparent: rgba(0x00000000).into(), + mac_os_traffic_light_red: rgba(0xec695eff).into(), + mac_os_traffic_light_yellow: rgba(0xf4bf4eff).into(), + mac_os_traffic_light_green: rgba(0x61c553ff).into(), + border: rgba(0xaaa3a1ff).into(), + border_variant: rgba(0xaaa3a1ff).into(), + border_focused: rgba(0xc6cef7ff).into(), + border_transparent: rgba(0x00000000).into(), + elevated_surface: rgba(0xccc7c5ff).into(), + surface: rgba(0xe9e6e4ff).into(), + background: rgba(0xccc7c5ff).into(), + filled_element: rgba(0xccc7c5ff).into(), + filled_element_hover: rgba(0xffffff1e).into(), + filled_element_active: rgba(0xffffff28).into(), + filled_element_selected: rgba(0xdfe3fbff).into(), + filled_element_disabled: rgba(0x00000000).into(), + ghost_element: rgba(0x00000000).into(), + ghost_element_hover: rgba(0xffffff14).into(), + ghost_element_active: rgba(0xffffff1e).into(), + ghost_element_selected: rgba(0xdfe3fbff).into(), + ghost_element_disabled: rgba(0x00000000).into(), + text: rgba(0x1b1918ff).into(), + text_muted: rgba(0x6a6360ff).into(), + text_placeholder: rgba(0xf22e40ff).into(), + text_disabled: rgba(0x837b78ff).into(), + text_accent: rgba(0x407ee6ff).into(), + icon_muted: rgba(0x6a6360ff).into(), + syntax: SyntaxTheme { + highlights: vec![ + ("punctuation.special".into(), rgba(0xc33ff3ff).into()), + ("text.literal".into(), rgba(0xdf5421ff).into()), + ("string.escape".into(), rgba(0x68615eff).into()), + ("string.regex".into(), rgba(0x3c96b8ff).into()), + ("number".into(), rgba(0xdf521fff).into()), + ("preproc".into(), rgba(0x1b1918ff).into()), + ("keyword".into(), rgba(0x6666eaff).into()), + ("variable.special".into(), rgba(0x6666eaff).into()), + ("punctuation.delimiter".into(), rgba(0x68615eff).into()), + ("emphasis.strong".into(), rgba(0x407ee6ff).into()), + ("boolean".into(), rgba(0x7a9728ff).into()), + ("variant".into(), rgba(0xc38417ff).into()), + ("predictive".into(), rgba(0xbe899eff).into()), + ("tag".into(), rgba(0x407ee6ff).into()), + ("property".into(), rgba(0xf22c40ff).into()), + ("enum".into(), rgba(0xdf5421ff).into()), + ("attribute".into(), rgba(0x407ee6ff).into()), + ("function.method".into(), rgba(0x3f7ee7ff).into()), + ("function".into(), rgba(0x3f7ee7ff).into()), + ("emphasis".into(), rgba(0x407ee6ff).into()), + ("primary".into(), rgba(0x2c2421ff).into()), + ("variable".into(), rgba(0x2c2421ff).into()), + ("constant".into(), rgba(0x7a9728ff).into()), + ("title".into(), rgba(0x1b1918ff).into()), + ("comment.doc".into(), rgba(0x68615eff).into()), + ("constructor".into(), rgba(0x407ee6ff).into()), + ("type".into(), rgba(0xc38417ff).into()), + ("punctuation.list_marker".into(), rgba(0x2c2421ff).into()), + ("punctuation".into(), rgba(0x2c2421ff).into()), + ("string".into(), rgba(0x7a9725ff).into()), + ("label".into(), rgba(0x407ee6ff).into()), + ("string.special".into(), rgba(0xc33ff3ff).into()), + ("embedded".into(), rgba(0x1b1918ff).into()), + ("link_text".into(), rgba(0xdf5421ff).into()), + ("punctuation.bracket".into(), rgba(0x68615eff).into()), + ("comment".into(), rgba(0x9c9491ff).into()), + ( + "function.special.definition".into(), + rgba(0xc38417ff).into(), + ), + ("link_uri".into(), rgba(0x7a9728ff).into()), + ("operator".into(), rgba(0x68615eff).into()), + ("hint".into(), rgba(0xa67287ff).into()), + ("string.special.symbol".into(), rgba(0x7a9725ff).into()), + ], + }, + status_bar: rgba(0xccc7c5ff).into(), + title_bar: rgba(0xccc7c5ff).into(), + toolbar: rgba(0xf0eeedff).into(), + tab_bar: rgba(0xe9e6e4ff).into(), + editor: rgba(0xf0eeedff).into(), + editor_subheader: rgba(0xe9e6e4ff).into(), + editor_active_line: rgba(0xe9e6e4ff).into(), + terminal: rgba(0xf0eeedff).into(), + image_fallback_background: rgba(0xccc7c5ff).into(), + git_created: rgba(0x7a9728ff).into(), + git_modified: rgba(0x407ee6ff).into(), + git_deleted: rgba(0xf22e40ff).into(), + git_conflict: rgba(0xc38419ff).into(), + git_ignored: rgba(0x837b78ff).into(), + git_renamed: rgba(0xc38419ff).into(), + players: [ + PlayerTheme { + cursor: rgba(0x407ee6ff).into(), + selection: rgba(0x407ee63d).into(), + }, + PlayerTheme { + cursor: rgba(0x7a9728ff).into(), + selection: rgba(0x7a97283d).into(), + }, + PlayerTheme { + cursor: rgba(0xc340f2ff).into(), + selection: rgba(0xc340f23d).into(), + }, + PlayerTheme { + cursor: rgba(0xdf5421ff).into(), + selection: rgba(0xdf54213d).into(), + }, + PlayerTheme { + cursor: rgba(0x6765e9ff).into(), + selection: rgba(0x6765e93d).into(), + }, + PlayerTheme { + cursor: rgba(0x3e96b8ff).into(), + selection: rgba(0x3e96b83d).into(), + }, + PlayerTheme { + cursor: rgba(0xf22e40ff).into(), + selection: rgba(0xf22e403d).into(), + }, + PlayerTheme { + cursor: rgba(0xc38419ff).into(), + selection: rgba(0xc384193d).into(), + }, + ], + } +} diff --git a/crates/theme2/src/themes/atelier_heath_dark.rs b/crates/theme2/src/themes/atelier_heath_dark.rs new file mode 100644 index 0000000000..354c98069f --- /dev/null +++ b/crates/theme2/src/themes/atelier_heath_dark.rs @@ -0,0 +1,136 @@ +use gpui2::rgba; + +use crate::{PlayerTheme, SyntaxTheme, Theme, ThemeMetadata}; + +pub fn atelier_heath_dark() -> Theme { + Theme { + metadata: ThemeMetadata { + name: "Atelier Heath Dark".into(), + is_light: false, + }, + transparent: rgba(0x00000000).into(), + mac_os_traffic_light_red: rgba(0xec695eff).into(), + mac_os_traffic_light_yellow: rgba(0xf4bf4eff).into(), + mac_os_traffic_light_green: rgba(0x61c553ff).into(), + border: rgba(0x675b67ff).into(), + border_variant: rgba(0x675b67ff).into(), + border_focused: rgba(0x192961ff).into(), + border_transparent: rgba(0x00000000).into(), + elevated_surface: rgba(0x433a43ff).into(), + surface: rgba(0x252025ff).into(), + background: rgba(0x433a43ff).into(), + filled_element: rgba(0x433a43ff).into(), + filled_element_hover: rgba(0xffffff1e).into(), + filled_element_active: rgba(0xffffff28).into(), + filled_element_selected: rgba(0x0d1a43ff).into(), + filled_element_disabled: rgba(0x00000000).into(), + ghost_element: rgba(0x00000000).into(), + ghost_element_hover: rgba(0xffffff14).into(), + ghost_element_active: rgba(0xffffff1e).into(), + ghost_element_selected: rgba(0x0d1a43ff).into(), + ghost_element_disabled: rgba(0x00000000).into(), + text: rgba(0xf7f3f7ff).into(), + text_muted: rgba(0xa899a8ff).into(), + text_placeholder: rgba(0xca3f2bff).into(), + text_disabled: rgba(0x908190ff).into(), + text_accent: rgba(0x5169ebff).into(), + icon_muted: rgba(0xa899a8ff).into(), + syntax: SyntaxTheme { + highlights: vec![ + ("preproc".into(), rgba(0xf7f3f7ff).into()), + ("number".into(), rgba(0xa65825ff).into()), + ("boolean".into(), rgba(0x918b3aff).into()), + ("embedded".into(), rgba(0xf7f3f7ff).into()), + ("variable.special".into(), rgba(0x7b58bfff).into()), + ("operator".into(), rgba(0xab9babff).into()), + ("punctuation.delimiter".into(), rgba(0xab9babff).into()), + ("primary".into(), rgba(0xd8cad8ff).into()), + ("punctuation.bracket".into(), rgba(0xab9babff).into()), + ("comment.doc".into(), rgba(0xab9babff).into()), + ("variant".into(), rgba(0xbb8a34ff).into()), + ("attribute".into(), rgba(0x5169ebff).into()), + ("property".into(), rgba(0xca3f2aff).into()), + ("keyword".into(), rgba(0x7b58bfff).into()), + ("hint".into(), rgba(0x8d70a8ff).into()), + ("string.special.symbol".into(), rgba(0x918b3aff).into()), + ("punctuation.special".into(), rgba(0xcc32ccff).into()), + ("link_uri".into(), rgba(0x918b3aff).into()), + ("link_text".into(), rgba(0xa65827ff).into()), + ("enum".into(), rgba(0xa65827ff).into()), + ("function".into(), rgba(0x506aecff).into()), + ( + "function.special.definition".into(), + rgba(0xbb8a34ff).into(), + ), + ("constant".into(), rgba(0x918b3aff).into()), + ("title".into(), rgba(0xf7f3f7ff).into()), + ("string.regex".into(), rgba(0x149393ff).into()), + ("variable".into(), rgba(0xd8cad8ff).into()), + ("comment".into(), rgba(0x776977ff).into()), + ("predictive".into(), rgba(0x75588fff).into()), + ("function.method".into(), rgba(0x506aecff).into()), + ("type".into(), rgba(0xbb8a34ff).into()), + ("punctuation".into(), rgba(0xd8cad8ff).into()), + ("emphasis".into(), rgba(0x5169ebff).into()), + ("emphasis.strong".into(), rgba(0x5169ebff).into()), + ("tag".into(), rgba(0x5169ebff).into()), + ("text.literal".into(), rgba(0xa65827ff).into()), + ("string".into(), rgba(0x918b3aff).into()), + ("string.escape".into(), rgba(0xab9babff).into()), + ("constructor".into(), rgba(0x5169ebff).into()), + ("label".into(), rgba(0x5169ebff).into()), + ("punctuation.list_marker".into(), rgba(0xd8cad8ff).into()), + ("string.special".into(), rgba(0xcc32ccff).into()), + ], + }, + status_bar: rgba(0x433a43ff).into(), + title_bar: rgba(0x433a43ff).into(), + toolbar: rgba(0x1b181bff).into(), + tab_bar: rgba(0x252025ff).into(), + editor: rgba(0x1b181bff).into(), + editor_subheader: rgba(0x252025ff).into(), + editor_active_line: rgba(0x252025ff).into(), + terminal: rgba(0x1b181bff).into(), + image_fallback_background: rgba(0x433a43ff).into(), + git_created: rgba(0x918b3aff).into(), + git_modified: rgba(0x5169ebff).into(), + git_deleted: rgba(0xca3f2bff).into(), + git_conflict: rgba(0xbb8a35ff).into(), + git_ignored: rgba(0x908190ff).into(), + git_renamed: rgba(0xbb8a35ff).into(), + players: [ + PlayerTheme { + cursor: rgba(0x5169ebff).into(), + selection: rgba(0x5169eb3d).into(), + }, + PlayerTheme { + cursor: rgba(0x918b3aff).into(), + selection: rgba(0x918b3a3d).into(), + }, + PlayerTheme { + cursor: rgba(0xcc34ccff).into(), + selection: rgba(0xcc34cc3d).into(), + }, + PlayerTheme { + cursor: rgba(0xa65827ff).into(), + selection: rgba(0xa658273d).into(), + }, + PlayerTheme { + cursor: rgba(0x7b58bfff).into(), + selection: rgba(0x7b58bf3d).into(), + }, + PlayerTheme { + cursor: rgba(0x189393ff).into(), + selection: rgba(0x1893933d).into(), + }, + PlayerTheme { + cursor: rgba(0xca3f2bff).into(), + selection: rgba(0xca3f2b3d).into(), + }, + PlayerTheme { + cursor: rgba(0xbb8a35ff).into(), + selection: rgba(0xbb8a353d).into(), + }, + ], + } +} diff --git a/crates/theme2/src/themes/atelier_heath_light.rs b/crates/theme2/src/themes/atelier_heath_light.rs new file mode 100644 index 0000000000..f1a9e4d8c6 --- /dev/null +++ b/crates/theme2/src/themes/atelier_heath_light.rs @@ -0,0 +1,136 @@ +use gpui2::rgba; + +use crate::{PlayerTheme, SyntaxTheme, Theme, ThemeMetadata}; + +pub fn atelier_heath_light() -> Theme { + Theme { + metadata: ThemeMetadata { + name: "Atelier Heath Light".into(), + is_light: true, + }, + transparent: rgba(0x00000000).into(), + mac_os_traffic_light_red: rgba(0xec695eff).into(), + mac_os_traffic_light_yellow: rgba(0xf4bf4eff).into(), + mac_os_traffic_light_green: rgba(0x61c553ff).into(), + border: rgba(0xad9dadff).into(), + border_variant: rgba(0xad9dadff).into(), + border_focused: rgba(0xcac7faff).into(), + border_transparent: rgba(0x00000000).into(), + elevated_surface: rgba(0xc6b8c6ff).into(), + surface: rgba(0xe0d5e0ff).into(), + background: rgba(0xc6b8c6ff).into(), + filled_element: rgba(0xc6b8c6ff).into(), + filled_element_hover: rgba(0xffffff1e).into(), + filled_element_active: rgba(0xffffff28).into(), + filled_element_selected: rgba(0xe2dffcff).into(), + filled_element_disabled: rgba(0x00000000).into(), + ghost_element: rgba(0x00000000).into(), + ghost_element_hover: rgba(0xffffff14).into(), + ghost_element_active: rgba(0xffffff1e).into(), + ghost_element_selected: rgba(0xe2dffcff).into(), + ghost_element_disabled: rgba(0x00000000).into(), + text: rgba(0x1b181bff).into(), + text_muted: rgba(0x6b5e6bff).into(), + text_placeholder: rgba(0xca402bff).into(), + text_disabled: rgba(0x857785ff).into(), + text_accent: rgba(0x5169ebff).into(), + icon_muted: rgba(0x6b5e6bff).into(), + syntax: SyntaxTheme { + highlights: vec![ + ("enum".into(), rgba(0xa65927ff).into()), + ("string.escape".into(), rgba(0x695d69ff).into()), + ("link_uri".into(), rgba(0x918b3bff).into()), + ("function.method".into(), rgba(0x506aecff).into()), + ("comment.doc".into(), rgba(0x695d69ff).into()), + ("property".into(), rgba(0xca3f2aff).into()), + ("string.special".into(), rgba(0xcc32ccff).into()), + ("tag".into(), rgba(0x5169ebff).into()), + ("embedded".into(), rgba(0x1b181bff).into()), + ("primary".into(), rgba(0x292329ff).into()), + ("punctuation".into(), rgba(0x292329ff).into()), + ("punctuation.special".into(), rgba(0xcc32ccff).into()), + ("type".into(), rgba(0xbb8a34ff).into()), + ("number".into(), rgba(0xa65825ff).into()), + ("function".into(), rgba(0x506aecff).into()), + ("preproc".into(), rgba(0x1b181bff).into()), + ("punctuation.bracket".into(), rgba(0x695d69ff).into()), + ("punctuation.delimiter".into(), rgba(0x695d69ff).into()), + ("variable".into(), rgba(0x292329ff).into()), + ( + "function.special.definition".into(), + rgba(0xbb8a34ff).into(), + ), + ("label".into(), rgba(0x5169ebff).into()), + ("constructor".into(), rgba(0x5169ebff).into()), + ("emphasis.strong".into(), rgba(0x5169ebff).into()), + ("constant".into(), rgba(0x918b3bff).into()), + ("keyword".into(), rgba(0x7b58bfff).into()), + ("variable.special".into(), rgba(0x7b58bfff).into()), + ("variant".into(), rgba(0xbb8a34ff).into()), + ("title".into(), rgba(0x1b181bff).into()), + ("attribute".into(), rgba(0x5169ebff).into()), + ("comment".into(), rgba(0x9e8f9eff).into()), + ("string.special.symbol".into(), rgba(0x918b3aff).into()), + ("predictive".into(), rgba(0xa487bfff).into()), + ("link_text".into(), rgba(0xa65927ff).into()), + ("punctuation.list_marker".into(), rgba(0x292329ff).into()), + ("boolean".into(), rgba(0x918b3bff).into()), + ("text.literal".into(), rgba(0xa65927ff).into()), + ("emphasis".into(), rgba(0x5169ebff).into()), + ("string.regex".into(), rgba(0x149393ff).into()), + ("hint".into(), rgba(0x8c70a6ff).into()), + ("string".into(), rgba(0x918b3aff).into()), + ("operator".into(), rgba(0x695d69ff).into()), + ], + }, + status_bar: rgba(0xc6b8c6ff).into(), + title_bar: rgba(0xc6b8c6ff).into(), + toolbar: rgba(0xf7f3f7ff).into(), + tab_bar: rgba(0xe0d5e0ff).into(), + editor: rgba(0xf7f3f7ff).into(), + editor_subheader: rgba(0xe0d5e0ff).into(), + editor_active_line: rgba(0xe0d5e0ff).into(), + terminal: rgba(0xf7f3f7ff).into(), + image_fallback_background: rgba(0xc6b8c6ff).into(), + git_created: rgba(0x918b3bff).into(), + git_modified: rgba(0x5169ebff).into(), + git_deleted: rgba(0xca402bff).into(), + git_conflict: rgba(0xbb8a35ff).into(), + git_ignored: rgba(0x857785ff).into(), + git_renamed: rgba(0xbb8a35ff).into(), + players: [ + PlayerTheme { + cursor: rgba(0x5169ebff).into(), + selection: rgba(0x5169eb3d).into(), + }, + PlayerTheme { + cursor: rgba(0x918b3bff).into(), + selection: rgba(0x918b3b3d).into(), + }, + PlayerTheme { + cursor: rgba(0xcc34ccff).into(), + selection: rgba(0xcc34cc3d).into(), + }, + PlayerTheme { + cursor: rgba(0xa65927ff).into(), + selection: rgba(0xa659273d).into(), + }, + PlayerTheme { + cursor: rgba(0x7a5ac0ff).into(), + selection: rgba(0x7a5ac03d).into(), + }, + PlayerTheme { + cursor: rgba(0x189393ff).into(), + selection: rgba(0x1893933d).into(), + }, + PlayerTheme { + cursor: rgba(0xca402bff).into(), + selection: rgba(0xca402b3d).into(), + }, + PlayerTheme { + cursor: rgba(0xbb8a35ff).into(), + selection: rgba(0xbb8a353d).into(), + }, + ], + } +} diff --git a/crates/theme2/src/themes/atelier_lakeside_dark.rs b/crates/theme2/src/themes/atelier_lakeside_dark.rs new file mode 100644 index 0000000000..61b78864b7 --- /dev/null +++ b/crates/theme2/src/themes/atelier_lakeside_dark.rs @@ -0,0 +1,136 @@ +use gpui2::rgba; + +use crate::{PlayerTheme, SyntaxTheme, Theme, ThemeMetadata}; + +pub fn atelier_lakeside_dark() -> Theme { + Theme { + metadata: ThemeMetadata { + name: "Atelier Lakeside Dark".into(), + is_light: false, + }, + transparent: rgba(0x00000000).into(), + mac_os_traffic_light_red: rgba(0xec695eff).into(), + mac_os_traffic_light_yellow: rgba(0xf4bf4eff).into(), + mac_os_traffic_light_green: rgba(0x61c553ff).into(), + border: rgba(0x4f6a78ff).into(), + border_variant: rgba(0x4f6a78ff).into(), + border_focused: rgba(0x1a2f3cff).into(), + border_transparent: rgba(0x00000000).into(), + elevated_surface: rgba(0x33444dff).into(), + surface: rgba(0x1c2529ff).into(), + background: rgba(0x33444dff).into(), + filled_element: rgba(0x33444dff).into(), + filled_element_hover: rgba(0xffffff1e).into(), + filled_element_active: rgba(0xffffff28).into(), + filled_element_selected: rgba(0x121c24ff).into(), + filled_element_disabled: rgba(0x00000000).into(), + ghost_element: rgba(0x00000000).into(), + ghost_element_hover: rgba(0xffffff14).into(), + ghost_element_active: rgba(0xffffff1e).into(), + ghost_element_selected: rgba(0x121c24ff).into(), + ghost_element_disabled: rgba(0x00000000).into(), + text: rgba(0xebf8ffff).into(), + text_muted: rgba(0x7c9fb3ff).into(), + text_placeholder: rgba(0xd22e72ff).into(), + text_disabled: rgba(0x688c9dff).into(), + text_accent: rgba(0x267eadff).into(), + icon_muted: rgba(0x7c9fb3ff).into(), + syntax: SyntaxTheme { + highlights: vec![ + ("punctuation.bracket".into(), rgba(0x7ea2b4ff).into()), + ("punctuation.special".into(), rgba(0xb72cd2ff).into()), + ("property".into(), rgba(0xd22c72ff).into()), + ("function.method".into(), rgba(0x247eadff).into()), + ("comment".into(), rgba(0x5a7b8cff).into()), + ("constructor".into(), rgba(0x267eadff).into()), + ("boolean".into(), rgba(0x558c3aff).into()), + ("hint".into(), rgba(0x52809aff).into()), + ("label".into(), rgba(0x267eadff).into()), + ("string.special".into(), rgba(0xb72cd2ff).into()), + ("title".into(), rgba(0xebf8ffff).into()), + ("punctuation.list_marker".into(), rgba(0xc1e4f6ff).into()), + ("emphasis.strong".into(), rgba(0x267eadff).into()), + ("enum".into(), rgba(0x935b25ff).into()), + ("type".into(), rgba(0x8a8a0eff).into()), + ("tag".into(), rgba(0x267eadff).into()), + ("punctuation.delimiter".into(), rgba(0x7ea2b4ff).into()), + ("primary".into(), rgba(0xc1e4f6ff).into()), + ("link_text".into(), rgba(0x935b25ff).into()), + ("variable".into(), rgba(0xc1e4f6ff).into()), + ("variable.special".into(), rgba(0x6a6ab7ff).into()), + ("string.special.symbol".into(), rgba(0x558c3aff).into()), + ("link_uri".into(), rgba(0x558c3aff).into()), + ("function".into(), rgba(0x247eadff).into()), + ("predictive".into(), rgba(0x426f88ff).into()), + ("punctuation".into(), rgba(0xc1e4f6ff).into()), + ("string.escape".into(), rgba(0x7ea2b4ff).into()), + ("keyword".into(), rgba(0x6a6ab7ff).into()), + ("attribute".into(), rgba(0x267eadff).into()), + ("string.regex".into(), rgba(0x2c8f6eff).into()), + ("embedded".into(), rgba(0xebf8ffff).into()), + ("emphasis".into(), rgba(0x267eadff).into()), + ("string".into(), rgba(0x558c3aff).into()), + ("operator".into(), rgba(0x7ea2b4ff).into()), + ("text.literal".into(), rgba(0x935b25ff).into()), + ("constant".into(), rgba(0x558c3aff).into()), + ("comment.doc".into(), rgba(0x7ea2b4ff).into()), + ("number".into(), rgba(0x935c24ff).into()), + ("preproc".into(), rgba(0xebf8ffff).into()), + ( + "function.special.definition".into(), + rgba(0x8a8a0eff).into(), + ), + ("variant".into(), rgba(0x8a8a0eff).into()), + ], + }, + status_bar: rgba(0x33444dff).into(), + title_bar: rgba(0x33444dff).into(), + toolbar: rgba(0x161b1dff).into(), + tab_bar: rgba(0x1c2529ff).into(), + editor: rgba(0x161b1dff).into(), + editor_subheader: rgba(0x1c2529ff).into(), + editor_active_line: rgba(0x1c2529ff).into(), + terminal: rgba(0x161b1dff).into(), + image_fallback_background: rgba(0x33444dff).into(), + git_created: rgba(0x558c3aff).into(), + git_modified: rgba(0x267eadff).into(), + git_deleted: rgba(0xd22e72ff).into(), + git_conflict: rgba(0x8a8a10ff).into(), + git_ignored: rgba(0x688c9dff).into(), + git_renamed: rgba(0x8a8a10ff).into(), + players: [ + PlayerTheme { + cursor: rgba(0x267eadff).into(), + selection: rgba(0x267ead3d).into(), + }, + PlayerTheme { + cursor: rgba(0x558c3aff).into(), + selection: rgba(0x558c3a3d).into(), + }, + PlayerTheme { + cursor: rgba(0xb72ed2ff).into(), + selection: rgba(0xb72ed23d).into(), + }, + PlayerTheme { + cursor: rgba(0x935b25ff).into(), + selection: rgba(0x935b253d).into(), + }, + PlayerTheme { + cursor: rgba(0x6a6ab7ff).into(), + selection: rgba(0x6a6ab73d).into(), + }, + PlayerTheme { + cursor: rgba(0x2d8f6fff).into(), + selection: rgba(0x2d8f6f3d).into(), + }, + PlayerTheme { + cursor: rgba(0xd22e72ff).into(), + selection: rgba(0xd22e723d).into(), + }, + PlayerTheme { + cursor: rgba(0x8a8a10ff).into(), + selection: rgba(0x8a8a103d).into(), + }, + ], + } +} diff --git a/crates/theme2/src/themes/atelier_lakeside_light.rs b/crates/theme2/src/themes/atelier_lakeside_light.rs new file mode 100644 index 0000000000..64fb70dadb --- /dev/null +++ b/crates/theme2/src/themes/atelier_lakeside_light.rs @@ -0,0 +1,136 @@ +use gpui2::rgba; + +use crate::{PlayerTheme, SyntaxTheme, Theme, ThemeMetadata}; + +pub fn atelier_lakeside_light() -> Theme { + Theme { + metadata: ThemeMetadata { + name: "Atelier Lakeside Light".into(), + is_light: true, + }, + transparent: rgba(0x00000000).into(), + mac_os_traffic_light_red: rgba(0xec695eff).into(), + mac_os_traffic_light_yellow: rgba(0xf4bf4eff).into(), + mac_os_traffic_light_green: rgba(0x61c553ff).into(), + border: rgba(0x80a4b6ff).into(), + border_variant: rgba(0x80a4b6ff).into(), + border_focused: rgba(0xb9cee0ff).into(), + border_transparent: rgba(0x00000000).into(), + elevated_surface: rgba(0xa6cadcff).into(), + surface: rgba(0xcdeaf9ff).into(), + background: rgba(0xa6cadcff).into(), + filled_element: rgba(0xa6cadcff).into(), + filled_element_hover: rgba(0xffffff1e).into(), + filled_element_active: rgba(0xffffff28).into(), + filled_element_selected: rgba(0xd8e4eeff).into(), + filled_element_disabled: rgba(0x00000000).into(), + ghost_element: rgba(0x00000000).into(), + ghost_element_hover: rgba(0xffffff14).into(), + ghost_element_active: rgba(0xffffff1e).into(), + ghost_element_selected: rgba(0xd8e4eeff).into(), + ghost_element_disabled: rgba(0x00000000).into(), + text: rgba(0x161b1dff).into(), + text_muted: rgba(0x526f7dff).into(), + text_placeholder: rgba(0xd22e71ff).into(), + text_disabled: rgba(0x628496ff).into(), + text_accent: rgba(0x267eadff).into(), + icon_muted: rgba(0x526f7dff).into(), + syntax: SyntaxTheme { + highlights: vec![ + ("emphasis".into(), rgba(0x267eadff).into()), + ("number".into(), rgba(0x935c24ff).into()), + ("embedded".into(), rgba(0x161b1dff).into()), + ("link_text".into(), rgba(0x935c25ff).into()), + ("string".into(), rgba(0x558c3aff).into()), + ("constructor".into(), rgba(0x267eadff).into()), + ("punctuation.list_marker".into(), rgba(0x1f292eff).into()), + ("string.special".into(), rgba(0xb72cd2ff).into()), + ("title".into(), rgba(0x161b1dff).into()), + ("variant".into(), rgba(0x8a8a0eff).into()), + ("tag".into(), rgba(0x267eadff).into()), + ("attribute".into(), rgba(0x267eadff).into()), + ("keyword".into(), rgba(0x6a6ab7ff).into()), + ("enum".into(), rgba(0x935c25ff).into()), + ("function".into(), rgba(0x247eadff).into()), + ("string.escape".into(), rgba(0x516d7bff).into()), + ("operator".into(), rgba(0x516d7bff).into()), + ("function.method".into(), rgba(0x247eadff).into()), + ( + "function.special.definition".into(), + rgba(0x8a8a0eff).into(), + ), + ("punctuation.delimiter".into(), rgba(0x516d7bff).into()), + ("comment".into(), rgba(0x7094a7ff).into()), + ("primary".into(), rgba(0x1f292eff).into()), + ("punctuation.bracket".into(), rgba(0x516d7bff).into()), + ("variable".into(), rgba(0x1f292eff).into()), + ("emphasis.strong".into(), rgba(0x267eadff).into()), + ("predictive".into(), rgba(0x6a97b2ff).into()), + ("punctuation.special".into(), rgba(0xb72cd2ff).into()), + ("hint".into(), rgba(0x5a87a0ff).into()), + ("text.literal".into(), rgba(0x935c25ff).into()), + ("string.special.symbol".into(), rgba(0x558c3aff).into()), + ("comment.doc".into(), rgba(0x516d7bff).into()), + ("constant".into(), rgba(0x568c3bff).into()), + ("boolean".into(), rgba(0x568c3bff).into()), + ("preproc".into(), rgba(0x161b1dff).into()), + ("variable.special".into(), rgba(0x6a6ab7ff).into()), + ("link_uri".into(), rgba(0x568c3bff).into()), + ("string.regex".into(), rgba(0x2c8f6eff).into()), + ("punctuation".into(), rgba(0x1f292eff).into()), + ("property".into(), rgba(0xd22c72ff).into()), + ("label".into(), rgba(0x267eadff).into()), + ("type".into(), rgba(0x8a8a0eff).into()), + ], + }, + status_bar: rgba(0xa6cadcff).into(), + title_bar: rgba(0xa6cadcff).into(), + toolbar: rgba(0xebf8ffff).into(), + tab_bar: rgba(0xcdeaf9ff).into(), + editor: rgba(0xebf8ffff).into(), + editor_subheader: rgba(0xcdeaf9ff).into(), + editor_active_line: rgba(0xcdeaf9ff).into(), + terminal: rgba(0xebf8ffff).into(), + image_fallback_background: rgba(0xa6cadcff).into(), + git_created: rgba(0x568c3bff).into(), + git_modified: rgba(0x267eadff).into(), + git_deleted: rgba(0xd22e71ff).into(), + git_conflict: rgba(0x8a8a10ff).into(), + git_ignored: rgba(0x628496ff).into(), + git_renamed: rgba(0x8a8a10ff).into(), + players: [ + PlayerTheme { + cursor: rgba(0x267eadff).into(), + selection: rgba(0x267ead3d).into(), + }, + PlayerTheme { + cursor: rgba(0x568c3bff).into(), + selection: rgba(0x568c3b3d).into(), + }, + PlayerTheme { + cursor: rgba(0xb72ed2ff).into(), + selection: rgba(0xb72ed23d).into(), + }, + PlayerTheme { + cursor: rgba(0x935c25ff).into(), + selection: rgba(0x935c253d).into(), + }, + PlayerTheme { + cursor: rgba(0x6c6ab7ff).into(), + selection: rgba(0x6c6ab73d).into(), + }, + PlayerTheme { + cursor: rgba(0x2e8f6eff).into(), + selection: rgba(0x2e8f6e3d).into(), + }, + PlayerTheme { + cursor: rgba(0xd22e71ff).into(), + selection: rgba(0xd22e713d).into(), + }, + PlayerTheme { + cursor: rgba(0x8a8a10ff).into(), + selection: rgba(0x8a8a103d).into(), + }, + ], + } +} diff --git a/crates/theme2/src/themes/atelier_plateau_dark.rs b/crates/theme2/src/themes/atelier_plateau_dark.rs new file mode 100644 index 0000000000..0ba5a1659d --- /dev/null +++ b/crates/theme2/src/themes/atelier_plateau_dark.rs @@ -0,0 +1,136 @@ +use gpui2::rgba; + +use crate::{PlayerTheme, SyntaxTheme, Theme, ThemeMetadata}; + +pub fn atelier_plateau_dark() -> Theme { + Theme { + metadata: ThemeMetadata { + name: "Atelier Plateau Dark".into(), + is_light: false, + }, + transparent: rgba(0x00000000).into(), + mac_os_traffic_light_red: rgba(0xec695eff).into(), + mac_os_traffic_light_yellow: rgba(0xf4bf4eff).into(), + mac_os_traffic_light_green: rgba(0x61c553ff).into(), + border: rgba(0x564e4eff).into(), + border_variant: rgba(0x564e4eff).into(), + border_focused: rgba(0x2c2b45ff).into(), + border_transparent: rgba(0x00000000).into(), + elevated_surface: rgba(0x3b3535ff).into(), + surface: rgba(0x252020ff).into(), + background: rgba(0x3b3535ff).into(), + filled_element: rgba(0x3b3535ff).into(), + filled_element_hover: rgba(0xffffff1e).into(), + filled_element_active: rgba(0xffffff28).into(), + filled_element_selected: rgba(0x1c1b29ff).into(), + filled_element_disabled: rgba(0x00000000).into(), + ghost_element: rgba(0x00000000).into(), + ghost_element_hover: rgba(0xffffff14).into(), + ghost_element_active: rgba(0xffffff1e).into(), + ghost_element_selected: rgba(0x1c1b29ff).into(), + ghost_element_disabled: rgba(0x00000000).into(), + text: rgba(0xf4ececff).into(), + text_muted: rgba(0x898383ff).into(), + text_placeholder: rgba(0xca4848ff).into(), + text_disabled: rgba(0x756e6eff).into(), + text_accent: rgba(0x7272caff).into(), + icon_muted: rgba(0x898383ff).into(), + syntax: SyntaxTheme { + highlights: vec![ + ("variant".into(), rgba(0xa06d3aff).into()), + ("label".into(), rgba(0x7272caff).into()), + ("punctuation.delimiter".into(), rgba(0x8a8585ff).into()), + ("string.regex".into(), rgba(0x5485b6ff).into()), + ("variable.special".into(), rgba(0x8464c4ff).into()), + ("string".into(), rgba(0x4b8b8bff).into()), + ("property".into(), rgba(0xca4848ff).into()), + ("hint".into(), rgba(0x8a647aff).into()), + ("comment.doc".into(), rgba(0x8a8585ff).into()), + ("attribute".into(), rgba(0x7272caff).into()), + ("tag".into(), rgba(0x7272caff).into()), + ("constructor".into(), rgba(0x7272caff).into()), + ("boolean".into(), rgba(0x4b8b8bff).into()), + ("preproc".into(), rgba(0xf4ececff).into()), + ("constant".into(), rgba(0x4b8b8bff).into()), + ("punctuation.special".into(), rgba(0xbd5187ff).into()), + ("function.method".into(), rgba(0x7272caff).into()), + ("comment".into(), rgba(0x655d5dff).into()), + ("variable".into(), rgba(0xe7dfdfff).into()), + ("primary".into(), rgba(0xe7dfdfff).into()), + ("title".into(), rgba(0xf4ececff).into()), + ("emphasis".into(), rgba(0x7272caff).into()), + ("emphasis.strong".into(), rgba(0x7272caff).into()), + ("function".into(), rgba(0x7272caff).into()), + ("type".into(), rgba(0xa06d3aff).into()), + ("operator".into(), rgba(0x8a8585ff).into()), + ("embedded".into(), rgba(0xf4ececff).into()), + ("predictive".into(), rgba(0x795369ff).into()), + ("punctuation".into(), rgba(0xe7dfdfff).into()), + ("link_text".into(), rgba(0xb4593bff).into()), + ("enum".into(), rgba(0xb4593bff).into()), + ("string.special".into(), rgba(0xbd5187ff).into()), + ("text.literal".into(), rgba(0xb4593bff).into()), + ("string.escape".into(), rgba(0x8a8585ff).into()), + ( + "function.special.definition".into(), + rgba(0xa06d3aff).into(), + ), + ("keyword".into(), rgba(0x8464c4ff).into()), + ("link_uri".into(), rgba(0x4b8b8bff).into()), + ("number".into(), rgba(0xb4593bff).into()), + ("punctuation.bracket".into(), rgba(0x8a8585ff).into()), + ("string.special.symbol".into(), rgba(0x4b8b8bff).into()), + ("punctuation.list_marker".into(), rgba(0xe7dfdfff).into()), + ], + }, + status_bar: rgba(0x3b3535ff).into(), + title_bar: rgba(0x3b3535ff).into(), + toolbar: rgba(0x1b1818ff).into(), + tab_bar: rgba(0x252020ff).into(), + editor: rgba(0x1b1818ff).into(), + editor_subheader: rgba(0x252020ff).into(), + editor_active_line: rgba(0x252020ff).into(), + terminal: rgba(0x1b1818ff).into(), + image_fallback_background: rgba(0x3b3535ff).into(), + git_created: rgba(0x4b8b8bff).into(), + git_modified: rgba(0x7272caff).into(), + git_deleted: rgba(0xca4848ff).into(), + git_conflict: rgba(0xa06d3aff).into(), + git_ignored: rgba(0x756e6eff).into(), + git_renamed: rgba(0xa06d3aff).into(), + players: [ + PlayerTheme { + cursor: rgba(0x7272caff).into(), + selection: rgba(0x7272ca3d).into(), + }, + PlayerTheme { + cursor: rgba(0x4b8b8bff).into(), + selection: rgba(0x4b8b8b3d).into(), + }, + PlayerTheme { + cursor: rgba(0xbd5187ff).into(), + selection: rgba(0xbd51873d).into(), + }, + PlayerTheme { + cursor: rgba(0xb4593bff).into(), + selection: rgba(0xb4593b3d).into(), + }, + PlayerTheme { + cursor: rgba(0x8464c4ff).into(), + selection: rgba(0x8464c43d).into(), + }, + PlayerTheme { + cursor: rgba(0x5485b6ff).into(), + selection: rgba(0x5485b63d).into(), + }, + PlayerTheme { + cursor: rgba(0xca4848ff).into(), + selection: rgba(0xca48483d).into(), + }, + PlayerTheme { + cursor: rgba(0xa06d3aff).into(), + selection: rgba(0xa06d3a3d).into(), + }, + ], + } +} diff --git a/crates/theme2/src/themes/atelier_plateau_light.rs b/crates/theme2/src/themes/atelier_plateau_light.rs new file mode 100644 index 0000000000..68f100dd85 --- /dev/null +++ b/crates/theme2/src/themes/atelier_plateau_light.rs @@ -0,0 +1,136 @@ +use gpui2::rgba; + +use crate::{PlayerTheme, SyntaxTheme, Theme, ThemeMetadata}; + +pub fn atelier_plateau_light() -> Theme { + Theme { + metadata: ThemeMetadata { + name: "Atelier Plateau Light".into(), + is_light: true, + }, + transparent: rgba(0x00000000).into(), + mac_os_traffic_light_red: rgba(0xec695eff).into(), + mac_os_traffic_light_yellow: rgba(0xf4bf4eff).into(), + mac_os_traffic_light_green: rgba(0x61c553ff).into(), + border: rgba(0x8e8989ff).into(), + border_variant: rgba(0x8e8989ff).into(), + border_focused: rgba(0xcecaecff).into(), + border_transparent: rgba(0x00000000).into(), + elevated_surface: rgba(0xc1bbbbff).into(), + surface: rgba(0xebe3e3ff).into(), + background: rgba(0xc1bbbbff).into(), + filled_element: rgba(0xc1bbbbff).into(), + filled_element_hover: rgba(0xffffff1e).into(), + filled_element_active: rgba(0xffffff28).into(), + filled_element_selected: rgba(0xe4e1f5ff).into(), + filled_element_disabled: rgba(0x00000000).into(), + ghost_element: rgba(0x00000000).into(), + ghost_element_hover: rgba(0xffffff14).into(), + ghost_element_active: rgba(0xffffff1e).into(), + ghost_element_selected: rgba(0xe4e1f5ff).into(), + ghost_element_disabled: rgba(0x00000000).into(), + text: rgba(0x1b1818ff).into(), + text_muted: rgba(0x5a5252ff).into(), + text_placeholder: rgba(0xca4a4aff).into(), + text_disabled: rgba(0x6e6666ff).into(), + text_accent: rgba(0x7272caff).into(), + icon_muted: rgba(0x5a5252ff).into(), + syntax: SyntaxTheme { + highlights: vec![ + ("text.literal".into(), rgba(0xb45a3cff).into()), + ("punctuation.special".into(), rgba(0xbd5187ff).into()), + ("variant".into(), rgba(0xa06d3aff).into()), + ("punctuation".into(), rgba(0x292424ff).into()), + ("string.escape".into(), rgba(0x585050ff).into()), + ("emphasis".into(), rgba(0x7272caff).into()), + ("title".into(), rgba(0x1b1818ff).into()), + ("constructor".into(), rgba(0x7272caff).into()), + ("variable".into(), rgba(0x292424ff).into()), + ("predictive".into(), rgba(0xa27a91ff).into()), + ("label".into(), rgba(0x7272caff).into()), + ("function.method".into(), rgba(0x7272caff).into()), + ("link_uri".into(), rgba(0x4c8b8bff).into()), + ("punctuation.delimiter".into(), rgba(0x585050ff).into()), + ("link_text".into(), rgba(0xb45a3cff).into()), + ("hint".into(), rgba(0x91697fff).into()), + ("emphasis.strong".into(), rgba(0x7272caff).into()), + ("attribute".into(), rgba(0x7272caff).into()), + ("boolean".into(), rgba(0x4c8b8bff).into()), + ("string.special.symbol".into(), rgba(0x4b8b8bff).into()), + ("string".into(), rgba(0x4b8b8bff).into()), + ("type".into(), rgba(0xa06d3aff).into()), + ("string.regex".into(), rgba(0x5485b6ff).into()), + ("comment.doc".into(), rgba(0x585050ff).into()), + ("string.special".into(), rgba(0xbd5187ff).into()), + ("property".into(), rgba(0xca4848ff).into()), + ("preproc".into(), rgba(0x1b1818ff).into()), + ("embedded".into(), rgba(0x1b1818ff).into()), + ("comment".into(), rgba(0x7e7777ff).into()), + ("primary".into(), rgba(0x292424ff).into()), + ("number".into(), rgba(0xb4593bff).into()), + ("function".into(), rgba(0x7272caff).into()), + ("punctuation.bracket".into(), rgba(0x585050ff).into()), + ("tag".into(), rgba(0x7272caff).into()), + ("punctuation.list_marker".into(), rgba(0x292424ff).into()), + ( + "function.special.definition".into(), + rgba(0xa06d3aff).into(), + ), + ("enum".into(), rgba(0xb45a3cff).into()), + ("keyword".into(), rgba(0x8464c4ff).into()), + ("operator".into(), rgba(0x585050ff).into()), + ("variable.special".into(), rgba(0x8464c4ff).into()), + ("constant".into(), rgba(0x4c8b8bff).into()), + ], + }, + status_bar: rgba(0xc1bbbbff).into(), + title_bar: rgba(0xc1bbbbff).into(), + toolbar: rgba(0xf4ececff).into(), + tab_bar: rgba(0xebe3e3ff).into(), + editor: rgba(0xf4ececff).into(), + editor_subheader: rgba(0xebe3e3ff).into(), + editor_active_line: rgba(0xebe3e3ff).into(), + terminal: rgba(0xf4ececff).into(), + image_fallback_background: rgba(0xc1bbbbff).into(), + git_created: rgba(0x4c8b8bff).into(), + git_modified: rgba(0x7272caff).into(), + git_deleted: rgba(0xca4a4aff).into(), + git_conflict: rgba(0xa06e3bff).into(), + git_ignored: rgba(0x6e6666ff).into(), + git_renamed: rgba(0xa06e3bff).into(), + players: [ + PlayerTheme { + cursor: rgba(0x7272caff).into(), + selection: rgba(0x7272ca3d).into(), + }, + PlayerTheme { + cursor: rgba(0x4c8b8bff).into(), + selection: rgba(0x4c8b8b3d).into(), + }, + PlayerTheme { + cursor: rgba(0xbd5186ff).into(), + selection: rgba(0xbd51863d).into(), + }, + PlayerTheme { + cursor: rgba(0xb45a3cff).into(), + selection: rgba(0xb45a3c3d).into(), + }, + PlayerTheme { + cursor: rgba(0x8464c4ff).into(), + selection: rgba(0x8464c43d).into(), + }, + PlayerTheme { + cursor: rgba(0x5485b5ff).into(), + selection: rgba(0x5485b53d).into(), + }, + PlayerTheme { + cursor: rgba(0xca4a4aff).into(), + selection: rgba(0xca4a4a3d).into(), + }, + PlayerTheme { + cursor: rgba(0xa06e3bff).into(), + selection: rgba(0xa06e3b3d).into(), + }, + ], + } +} diff --git a/crates/theme2/src/themes/atelier_savanna_dark.rs b/crates/theme2/src/themes/atelier_savanna_dark.rs new file mode 100644 index 0000000000..d4040db958 --- /dev/null +++ b/crates/theme2/src/themes/atelier_savanna_dark.rs @@ -0,0 +1,136 @@ +use gpui2::rgba; + +use crate::{PlayerTheme, SyntaxTheme, Theme, ThemeMetadata}; + +pub fn atelier_savanna_dark() -> Theme { + Theme { + metadata: ThemeMetadata { + name: "Atelier Savanna Dark".into(), + is_light: false, + }, + transparent: rgba(0x00000000).into(), + mac_os_traffic_light_red: rgba(0xec695eff).into(), + mac_os_traffic_light_yellow: rgba(0xf4bf4eff).into(), + mac_os_traffic_light_green: rgba(0x61c553ff).into(), + border: rgba(0x505e55ff).into(), + border_variant: rgba(0x505e55ff).into(), + border_focused: rgba(0x1f3233ff).into(), + border_transparent: rgba(0x00000000).into(), + elevated_surface: rgba(0x353f39ff).into(), + surface: rgba(0x1f2621ff).into(), + background: rgba(0x353f39ff).into(), + filled_element: rgba(0x353f39ff).into(), + filled_element_hover: rgba(0xffffff1e).into(), + filled_element_active: rgba(0xffffff28).into(), + filled_element_selected: rgba(0x151e20ff).into(), + filled_element_disabled: rgba(0x00000000).into(), + ghost_element: rgba(0x00000000).into(), + ghost_element_hover: rgba(0xffffff14).into(), + ghost_element_active: rgba(0xffffff1e).into(), + ghost_element_selected: rgba(0x151e20ff).into(), + ghost_element_disabled: rgba(0x00000000).into(), + text: rgba(0xecf4eeff).into(), + text_muted: rgba(0x859188ff).into(), + text_placeholder: rgba(0xb16038ff).into(), + text_disabled: rgba(0x6f7e74ff).into(), + text_accent: rgba(0x468b8fff).into(), + icon_muted: rgba(0x859188ff).into(), + syntax: SyntaxTheme { + highlights: vec![ + ("function.method".into(), rgba(0x468b8fff).into()), + ("title".into(), rgba(0xecf4eeff).into()), + ("label".into(), rgba(0x468b8fff).into()), + ("text.literal".into(), rgba(0x9f703bff).into()), + ("boolean".into(), rgba(0x479962ff).into()), + ("punctuation.list_marker".into(), rgba(0xdfe7e2ff).into()), + ("string.escape".into(), rgba(0x87928aff).into()), + ("string.special".into(), rgba(0x857368ff).into()), + ("punctuation.delimiter".into(), rgba(0x87928aff).into()), + ("tag".into(), rgba(0x468b8fff).into()), + ("property".into(), rgba(0xb16038ff).into()), + ("preproc".into(), rgba(0xecf4eeff).into()), + ("primary".into(), rgba(0xdfe7e2ff).into()), + ("link_uri".into(), rgba(0x479962ff).into()), + ("comment".into(), rgba(0x5f6d64ff).into()), + ("type".into(), rgba(0xa07d3aff).into()), + ("hint".into(), rgba(0x607e76ff).into()), + ("punctuation".into(), rgba(0xdfe7e2ff).into()), + ("string.special.symbol".into(), rgba(0x479962ff).into()), + ("emphasis.strong".into(), rgba(0x468b8fff).into()), + ("keyword".into(), rgba(0x55859bff).into()), + ("comment.doc".into(), rgba(0x87928aff).into()), + ("punctuation.bracket".into(), rgba(0x87928aff).into()), + ("constant".into(), rgba(0x479962ff).into()), + ("link_text".into(), rgba(0x9f703bff).into()), + ("number".into(), rgba(0x9f703bff).into()), + ("function".into(), rgba(0x468b8fff).into()), + ("variable".into(), rgba(0xdfe7e2ff).into()), + ("emphasis".into(), rgba(0x468b8fff).into()), + ("punctuation.special".into(), rgba(0x857368ff).into()), + ("constructor".into(), rgba(0x468b8fff).into()), + ("variable.special".into(), rgba(0x55859bff).into()), + ("operator".into(), rgba(0x87928aff).into()), + ("enum".into(), rgba(0x9f703bff).into()), + ("string.regex".into(), rgba(0x1b9aa0ff).into()), + ("attribute".into(), rgba(0x468b8fff).into()), + ("predictive".into(), rgba(0x506d66ff).into()), + ("string".into(), rgba(0x479962ff).into()), + ("embedded".into(), rgba(0xecf4eeff).into()), + ("variant".into(), rgba(0xa07d3aff).into()), + ( + "function.special.definition".into(), + rgba(0xa07d3aff).into(), + ), + ], + }, + status_bar: rgba(0x353f39ff).into(), + title_bar: rgba(0x353f39ff).into(), + toolbar: rgba(0x171c19ff).into(), + tab_bar: rgba(0x1f2621ff).into(), + editor: rgba(0x171c19ff).into(), + editor_subheader: rgba(0x1f2621ff).into(), + editor_active_line: rgba(0x1f2621ff).into(), + terminal: rgba(0x171c19ff).into(), + image_fallback_background: rgba(0x353f39ff).into(), + git_created: rgba(0x479962ff).into(), + git_modified: rgba(0x468b8fff).into(), + git_deleted: rgba(0xb16038ff).into(), + git_conflict: rgba(0xa07d3aff).into(), + git_ignored: rgba(0x6f7e74ff).into(), + git_renamed: rgba(0xa07d3aff).into(), + players: [ + PlayerTheme { + cursor: rgba(0x468b8fff).into(), + selection: rgba(0x468b8f3d).into(), + }, + PlayerTheme { + cursor: rgba(0x479962ff).into(), + selection: rgba(0x4799623d).into(), + }, + PlayerTheme { + cursor: rgba(0x857368ff).into(), + selection: rgba(0x8573683d).into(), + }, + PlayerTheme { + cursor: rgba(0x9f703bff).into(), + selection: rgba(0x9f703b3d).into(), + }, + PlayerTheme { + cursor: rgba(0x55859bff).into(), + selection: rgba(0x55859b3d).into(), + }, + PlayerTheme { + cursor: rgba(0x1d9aa0ff).into(), + selection: rgba(0x1d9aa03d).into(), + }, + PlayerTheme { + cursor: rgba(0xb16038ff).into(), + selection: rgba(0xb160383d).into(), + }, + PlayerTheme { + cursor: rgba(0xa07d3aff).into(), + selection: rgba(0xa07d3a3d).into(), + }, + ], + } +} diff --git a/crates/theme2/src/themes/atelier_savanna_light.rs b/crates/theme2/src/themes/atelier_savanna_light.rs new file mode 100644 index 0000000000..08722cd91c --- /dev/null +++ b/crates/theme2/src/themes/atelier_savanna_light.rs @@ -0,0 +1,136 @@ +use gpui2::rgba; + +use crate::{PlayerTheme, SyntaxTheme, Theme, ThemeMetadata}; + +pub fn atelier_savanna_light() -> Theme { + Theme { + metadata: ThemeMetadata { + name: "Atelier Savanna Light".into(), + is_light: true, + }, + transparent: rgba(0x00000000).into(), + mac_os_traffic_light_red: rgba(0xec695eff).into(), + mac_os_traffic_light_yellow: rgba(0xf4bf4eff).into(), + mac_os_traffic_light_green: rgba(0x61c553ff).into(), + border: rgba(0x8b968eff).into(), + border_variant: rgba(0x8b968eff).into(), + border_focused: rgba(0xbed4d6ff).into(), + border_transparent: rgba(0x00000000).into(), + elevated_surface: rgba(0xbcc5bfff).into(), + surface: rgba(0xe3ebe6ff).into(), + background: rgba(0xbcc5bfff).into(), + filled_element: rgba(0xbcc5bfff).into(), + filled_element_hover: rgba(0xffffff1e).into(), + filled_element_active: rgba(0xffffff28).into(), + filled_element_selected: rgba(0xdae7e8ff).into(), + filled_element_disabled: rgba(0x00000000).into(), + ghost_element: rgba(0x00000000).into(), + ghost_element_hover: rgba(0xffffff14).into(), + ghost_element_active: rgba(0xffffff1e).into(), + ghost_element_selected: rgba(0xdae7e8ff).into(), + ghost_element_disabled: rgba(0x00000000).into(), + text: rgba(0x171c19ff).into(), + text_muted: rgba(0x546259ff).into(), + text_placeholder: rgba(0xb16139ff).into(), + text_disabled: rgba(0x68766dff).into(), + text_accent: rgba(0x488b90ff).into(), + icon_muted: rgba(0x546259ff).into(), + syntax: SyntaxTheme { + highlights: vec![ + ("text.literal".into(), rgba(0x9f713cff).into()), + ("string".into(), rgba(0x479962ff).into()), + ("punctuation.special".into(), rgba(0x857368ff).into()), + ("type".into(), rgba(0xa07d3aff).into()), + ("enum".into(), rgba(0x9f713cff).into()), + ("title".into(), rgba(0x171c19ff).into()), + ("comment".into(), rgba(0x77877cff).into()), + ("predictive".into(), rgba(0x75958bff).into()), + ("punctuation.list_marker".into(), rgba(0x232a25ff).into()), + ("string.special.symbol".into(), rgba(0x479962ff).into()), + ("constructor".into(), rgba(0x488b90ff).into()), + ("variable".into(), rgba(0x232a25ff).into()), + ("label".into(), rgba(0x488b90ff).into()), + ("attribute".into(), rgba(0x488b90ff).into()), + ("constant".into(), rgba(0x499963ff).into()), + ("function".into(), rgba(0x468b8fff).into()), + ("variable.special".into(), rgba(0x55859bff).into()), + ("keyword".into(), rgba(0x55859bff).into()), + ("number".into(), rgba(0x9f703bff).into()), + ("boolean".into(), rgba(0x499963ff).into()), + ("embedded".into(), rgba(0x171c19ff).into()), + ("string.special".into(), rgba(0x857368ff).into()), + ("emphasis.strong".into(), rgba(0x488b90ff).into()), + ("string.regex".into(), rgba(0x1b9aa0ff).into()), + ("hint".into(), rgba(0x66847cff).into()), + ("preproc".into(), rgba(0x171c19ff).into()), + ("link_uri".into(), rgba(0x499963ff).into()), + ("variant".into(), rgba(0xa07d3aff).into()), + ("function.method".into(), rgba(0x468b8fff).into()), + ("punctuation.bracket".into(), rgba(0x526057ff).into()), + ("punctuation.delimiter".into(), rgba(0x526057ff).into()), + ("punctuation".into(), rgba(0x232a25ff).into()), + ("primary".into(), rgba(0x232a25ff).into()), + ("string.escape".into(), rgba(0x526057ff).into()), + ("property".into(), rgba(0xb16038ff).into()), + ("operator".into(), rgba(0x526057ff).into()), + ("comment.doc".into(), rgba(0x526057ff).into()), + ( + "function.special.definition".into(), + rgba(0xa07d3aff).into(), + ), + ("link_text".into(), rgba(0x9f713cff).into()), + ("tag".into(), rgba(0x488b90ff).into()), + ("emphasis".into(), rgba(0x488b90ff).into()), + ], + }, + status_bar: rgba(0xbcc5bfff).into(), + title_bar: rgba(0xbcc5bfff).into(), + toolbar: rgba(0xecf4eeff).into(), + tab_bar: rgba(0xe3ebe6ff).into(), + editor: rgba(0xecf4eeff).into(), + editor_subheader: rgba(0xe3ebe6ff).into(), + editor_active_line: rgba(0xe3ebe6ff).into(), + terminal: rgba(0xecf4eeff).into(), + image_fallback_background: rgba(0xbcc5bfff).into(), + git_created: rgba(0x499963ff).into(), + git_modified: rgba(0x488b90ff).into(), + git_deleted: rgba(0xb16139ff).into(), + git_conflict: rgba(0xa07d3bff).into(), + git_ignored: rgba(0x68766dff).into(), + git_renamed: rgba(0xa07d3bff).into(), + players: [ + PlayerTheme { + cursor: rgba(0x488b90ff).into(), + selection: rgba(0x488b903d).into(), + }, + PlayerTheme { + cursor: rgba(0x499963ff).into(), + selection: rgba(0x4999633d).into(), + }, + PlayerTheme { + cursor: rgba(0x857368ff).into(), + selection: rgba(0x8573683d).into(), + }, + PlayerTheme { + cursor: rgba(0x9f713cff).into(), + selection: rgba(0x9f713c3d).into(), + }, + PlayerTheme { + cursor: rgba(0x55859bff).into(), + selection: rgba(0x55859b3d).into(), + }, + PlayerTheme { + cursor: rgba(0x1e9aa0ff).into(), + selection: rgba(0x1e9aa03d).into(), + }, + PlayerTheme { + cursor: rgba(0xb16139ff).into(), + selection: rgba(0xb161393d).into(), + }, + PlayerTheme { + cursor: rgba(0xa07d3bff).into(), + selection: rgba(0xa07d3b3d).into(), + }, + ], + } +} diff --git a/crates/theme2/src/themes/atelier_seaside_dark.rs b/crates/theme2/src/themes/atelier_seaside_dark.rs new file mode 100644 index 0000000000..475115e0d1 --- /dev/null +++ b/crates/theme2/src/themes/atelier_seaside_dark.rs @@ -0,0 +1,136 @@ +use gpui2::rgba; + +use crate::{PlayerTheme, SyntaxTheme, Theme, ThemeMetadata}; + +pub fn atelier_seaside_dark() -> Theme { + Theme { + metadata: ThemeMetadata { + name: "Atelier Seaside Dark".into(), + is_light: false, + }, + transparent: rgba(0x00000000).into(), + mac_os_traffic_light_red: rgba(0xec695eff).into(), + mac_os_traffic_light_yellow: rgba(0xf4bf4eff).into(), + mac_os_traffic_light_green: rgba(0x61c553ff).into(), + border: rgba(0x5c6c5cff).into(), + border_variant: rgba(0x5c6c5cff).into(), + border_focused: rgba(0x102667ff).into(), + border_transparent: rgba(0x00000000).into(), + elevated_surface: rgba(0x3b453bff).into(), + surface: rgba(0x1f231fff).into(), + background: rgba(0x3b453bff).into(), + filled_element: rgba(0x3b453bff).into(), + filled_element_hover: rgba(0xffffff1e).into(), + filled_element_active: rgba(0xffffff28).into(), + filled_element_selected: rgba(0x051949ff).into(), + filled_element_disabled: rgba(0x00000000).into(), + ghost_element: rgba(0x00000000).into(), + ghost_element_hover: rgba(0xffffff14).into(), + ghost_element_active: rgba(0xffffff1e).into(), + ghost_element_selected: rgba(0x051949ff).into(), + ghost_element_disabled: rgba(0x00000000).into(), + text: rgba(0xf3faf3ff).into(), + text_muted: rgba(0x8ba48bff).into(), + text_placeholder: rgba(0xe61c3bff).into(), + text_disabled: rgba(0x778f77ff).into(), + text_accent: rgba(0x3e62f4ff).into(), + icon_muted: rgba(0x8ba48bff).into(), + syntax: SyntaxTheme { + highlights: vec![ + ("comment".into(), rgba(0x687d68ff).into()), + ("predictive".into(), rgba(0x00788bff).into()), + ("string.special".into(), rgba(0xe618c3ff).into()), + ("string.regex".into(), rgba(0x1899b3ff).into()), + ("boolean".into(), rgba(0x2aa329ff).into()), + ("string".into(), rgba(0x28a328ff).into()), + ("operator".into(), rgba(0x8ca68cff).into()), + ("primary".into(), rgba(0xcfe8cfff).into()), + ("number".into(), rgba(0x87711cff).into()), + ("punctuation.special".into(), rgba(0xe618c3ff).into()), + ("link_text".into(), rgba(0x87711dff).into()), + ("title".into(), rgba(0xf3faf3ff).into()), + ("comment.doc".into(), rgba(0x8ca68cff).into()), + ("label".into(), rgba(0x3e62f4ff).into()), + ("preproc".into(), rgba(0xf3faf3ff).into()), + ("punctuation.bracket".into(), rgba(0x8ca68cff).into()), + ("punctuation.delimiter".into(), rgba(0x8ca68cff).into()), + ("function.method".into(), rgba(0x3d62f5ff).into()), + ("tag".into(), rgba(0x3e62f4ff).into()), + ("embedded".into(), rgba(0xf3faf3ff).into()), + ("text.literal".into(), rgba(0x87711dff).into()), + ("punctuation".into(), rgba(0xcfe8cfff).into()), + ("string.special.symbol".into(), rgba(0x28a328ff).into()), + ("link_uri".into(), rgba(0x2aa329ff).into()), + ("keyword".into(), rgba(0xac2aeeff).into()), + ("function".into(), rgba(0x3d62f5ff).into()), + ("string.escape".into(), rgba(0x8ca68cff).into()), + ("variant".into(), rgba(0x98981bff).into()), + ( + "function.special.definition".into(), + rgba(0x98981bff).into(), + ), + ("constructor".into(), rgba(0x3e62f4ff).into()), + ("constant".into(), rgba(0x2aa329ff).into()), + ("hint".into(), rgba(0x008b9fff).into()), + ("type".into(), rgba(0x98981bff).into()), + ("emphasis".into(), rgba(0x3e62f4ff).into()), + ("variable".into(), rgba(0xcfe8cfff).into()), + ("emphasis.strong".into(), rgba(0x3e62f4ff).into()), + ("attribute".into(), rgba(0x3e62f4ff).into()), + ("enum".into(), rgba(0x87711dff).into()), + ("property".into(), rgba(0xe6183bff).into()), + ("punctuation.list_marker".into(), rgba(0xcfe8cfff).into()), + ("variable.special".into(), rgba(0xac2aeeff).into()), + ], + }, + status_bar: rgba(0x3b453bff).into(), + title_bar: rgba(0x3b453bff).into(), + toolbar: rgba(0x131513ff).into(), + tab_bar: rgba(0x1f231fff).into(), + editor: rgba(0x131513ff).into(), + editor_subheader: rgba(0x1f231fff).into(), + editor_active_line: rgba(0x1f231fff).into(), + terminal: rgba(0x131513ff).into(), + image_fallback_background: rgba(0x3b453bff).into(), + git_created: rgba(0x2aa329ff).into(), + git_modified: rgba(0x3e62f4ff).into(), + git_deleted: rgba(0xe61c3bff).into(), + git_conflict: rgba(0x98981bff).into(), + git_ignored: rgba(0x778f77ff).into(), + git_renamed: rgba(0x98981bff).into(), + players: [ + PlayerTheme { + cursor: rgba(0x3e62f4ff).into(), + selection: rgba(0x3e62f43d).into(), + }, + PlayerTheme { + cursor: rgba(0x2aa329ff).into(), + selection: rgba(0x2aa3293d).into(), + }, + PlayerTheme { + cursor: rgba(0xe61cc3ff).into(), + selection: rgba(0xe61cc33d).into(), + }, + PlayerTheme { + cursor: rgba(0x87711dff).into(), + selection: rgba(0x87711d3d).into(), + }, + PlayerTheme { + cursor: rgba(0xac2dedff).into(), + selection: rgba(0xac2ded3d).into(), + }, + PlayerTheme { + cursor: rgba(0x1b99b3ff).into(), + selection: rgba(0x1b99b33d).into(), + }, + PlayerTheme { + cursor: rgba(0xe61c3bff).into(), + selection: rgba(0xe61c3b3d).into(), + }, + PlayerTheme { + cursor: rgba(0x98981bff).into(), + selection: rgba(0x98981b3d).into(), + }, + ], + } +} diff --git a/crates/theme2/src/themes/atelier_seaside_light.rs b/crates/theme2/src/themes/atelier_seaside_light.rs new file mode 100644 index 0000000000..557134b540 --- /dev/null +++ b/crates/theme2/src/themes/atelier_seaside_light.rs @@ -0,0 +1,136 @@ +use gpui2::rgba; + +use crate::{PlayerTheme, SyntaxTheme, Theme, ThemeMetadata}; + +pub fn atelier_seaside_light() -> Theme { + Theme { + metadata: ThemeMetadata { + name: "Atelier Seaside Light".into(), + is_light: true, + }, + transparent: rgba(0x00000000).into(), + mac_os_traffic_light_red: rgba(0xec695eff).into(), + mac_os_traffic_light_yellow: rgba(0xf4bf4eff).into(), + mac_os_traffic_light_green: rgba(0x61c553ff).into(), + border: rgba(0x8ea88eff).into(), + border_variant: rgba(0x8ea88eff).into(), + border_focused: rgba(0xc9c4fdff).into(), + border_transparent: rgba(0x00000000).into(), + elevated_surface: rgba(0xb4ceb4ff).into(), + surface: rgba(0xdaeedaff).into(), + background: rgba(0xb4ceb4ff).into(), + filled_element: rgba(0xb4ceb4ff).into(), + filled_element_hover: rgba(0xffffff1e).into(), + filled_element_active: rgba(0xffffff28).into(), + filled_element_selected: rgba(0xe1ddfeff).into(), + filled_element_disabled: rgba(0x00000000).into(), + ghost_element: rgba(0x00000000).into(), + ghost_element_hover: rgba(0xffffff14).into(), + ghost_element_active: rgba(0xffffff1e).into(), + ghost_element_selected: rgba(0xe1ddfeff).into(), + ghost_element_disabled: rgba(0x00000000).into(), + text: rgba(0x131513ff).into(), + text_muted: rgba(0x5f705fff).into(), + text_placeholder: rgba(0xe61c3dff).into(), + text_disabled: rgba(0x718771ff).into(), + text_accent: rgba(0x3e61f4ff).into(), + icon_muted: rgba(0x5f705fff).into(), + syntax: SyntaxTheme { + highlights: vec![ + ("string.escape".into(), rgba(0x5e6e5eff).into()), + ("boolean".into(), rgba(0x2aa32aff).into()), + ("string.special".into(), rgba(0xe618c3ff).into()), + ("comment".into(), rgba(0x809980ff).into()), + ("number".into(), rgba(0x87711cff).into()), + ("comment.doc".into(), rgba(0x5e6e5eff).into()), + ("tag".into(), rgba(0x3e61f4ff).into()), + ("string.special.symbol".into(), rgba(0x28a328ff).into()), + ("primary".into(), rgba(0x242924ff).into()), + ("string".into(), rgba(0x28a328ff).into()), + ("enum".into(), rgba(0x87711fff).into()), + ("operator".into(), rgba(0x5e6e5eff).into()), + ("string.regex".into(), rgba(0x1899b3ff).into()), + ("keyword".into(), rgba(0xac2aeeff).into()), + ("emphasis".into(), rgba(0x3e61f4ff).into()), + ("link_uri".into(), rgba(0x2aa32aff).into()), + ("constant".into(), rgba(0x2aa32aff).into()), + ("constructor".into(), rgba(0x3e61f4ff).into()), + ("link_text".into(), rgba(0x87711fff).into()), + ("emphasis.strong".into(), rgba(0x3e61f4ff).into()), + ("punctuation.list_marker".into(), rgba(0x242924ff).into()), + ("punctuation.delimiter".into(), rgba(0x5e6e5eff).into()), + ("punctuation.special".into(), rgba(0xe618c3ff).into()), + ("variant".into(), rgba(0x98981bff).into()), + ("predictive".into(), rgba(0x00a2b5ff).into()), + ("attribute".into(), rgba(0x3e61f4ff).into()), + ("preproc".into(), rgba(0x131513ff).into()), + ("embedded".into(), rgba(0x131513ff).into()), + ("punctuation".into(), rgba(0x242924ff).into()), + ("label".into(), rgba(0x3e61f4ff).into()), + ("function.method".into(), rgba(0x3d62f5ff).into()), + ("property".into(), rgba(0xe6183bff).into()), + ("title".into(), rgba(0x131513ff).into()), + ("variable".into(), rgba(0x242924ff).into()), + ("function".into(), rgba(0x3d62f5ff).into()), + ("variable.special".into(), rgba(0xac2aeeff).into()), + ("type".into(), rgba(0x98981bff).into()), + ("text.literal".into(), rgba(0x87711fff).into()), + ("hint".into(), rgba(0x008fa1ff).into()), + ( + "function.special.definition".into(), + rgba(0x98981bff).into(), + ), + ("punctuation.bracket".into(), rgba(0x5e6e5eff).into()), + ], + }, + status_bar: rgba(0xb4ceb4ff).into(), + title_bar: rgba(0xb4ceb4ff).into(), + toolbar: rgba(0xf3faf3ff).into(), + tab_bar: rgba(0xdaeedaff).into(), + editor: rgba(0xf3faf3ff).into(), + editor_subheader: rgba(0xdaeedaff).into(), + editor_active_line: rgba(0xdaeedaff).into(), + terminal: rgba(0xf3faf3ff).into(), + image_fallback_background: rgba(0xb4ceb4ff).into(), + git_created: rgba(0x2aa32aff).into(), + git_modified: rgba(0x3e61f4ff).into(), + git_deleted: rgba(0xe61c3dff).into(), + git_conflict: rgba(0x98981cff).into(), + git_ignored: rgba(0x718771ff).into(), + git_renamed: rgba(0x98981cff).into(), + players: [ + PlayerTheme { + cursor: rgba(0x3e61f4ff).into(), + selection: rgba(0x3e61f43d).into(), + }, + PlayerTheme { + cursor: rgba(0x2aa32aff).into(), + selection: rgba(0x2aa32a3d).into(), + }, + PlayerTheme { + cursor: rgba(0xe61cc2ff).into(), + selection: rgba(0xe61cc23d).into(), + }, + PlayerTheme { + cursor: rgba(0x87711fff).into(), + selection: rgba(0x87711f3d).into(), + }, + PlayerTheme { + cursor: rgba(0xac2dedff).into(), + selection: rgba(0xac2ded3d).into(), + }, + PlayerTheme { + cursor: rgba(0x1c99b3ff).into(), + selection: rgba(0x1c99b33d).into(), + }, + PlayerTheme { + cursor: rgba(0xe61c3dff).into(), + selection: rgba(0xe61c3d3d).into(), + }, + PlayerTheme { + cursor: rgba(0x98981cff).into(), + selection: rgba(0x98981c3d).into(), + }, + ], + } +} diff --git a/crates/theme2/src/themes/atelier_sulphurpool_dark.rs b/crates/theme2/src/themes/atelier_sulphurpool_dark.rs new file mode 100644 index 0000000000..8be8451740 --- /dev/null +++ b/crates/theme2/src/themes/atelier_sulphurpool_dark.rs @@ -0,0 +1,136 @@ +use gpui2::rgba; + +use crate::{PlayerTheme, SyntaxTheme, Theme, ThemeMetadata}; + +pub fn atelier_sulphurpool_dark() -> Theme { + Theme { + metadata: ThemeMetadata { + name: "Atelier Sulphurpool Dark".into(), + is_light: false, + }, + transparent: rgba(0x00000000).into(), + mac_os_traffic_light_red: rgba(0xec695eff).into(), + mac_os_traffic_light_yellow: rgba(0xf4bf4eff).into(), + mac_os_traffic_light_green: rgba(0x61c553ff).into(), + border: rgba(0x5b6385ff).into(), + border_variant: rgba(0x5b6385ff).into(), + border_focused: rgba(0x203348ff).into(), + border_transparent: rgba(0x00000000).into(), + elevated_surface: rgba(0x3e4769ff).into(), + surface: rgba(0x262f51ff).into(), + background: rgba(0x3e4769ff).into(), + filled_element: rgba(0x3e4769ff).into(), + filled_element_hover: rgba(0xffffff1e).into(), + filled_element_active: rgba(0xffffff28).into(), + filled_element_selected: rgba(0x161f2bff).into(), + filled_element_disabled: rgba(0x00000000).into(), + ghost_element: rgba(0x00000000).into(), + ghost_element_hover: rgba(0xffffff14).into(), + ghost_element_active: rgba(0xffffff1e).into(), + ghost_element_selected: rgba(0x161f2bff).into(), + ghost_element_disabled: rgba(0x00000000).into(), + text: rgba(0xf5f7ffff).into(), + text_muted: rgba(0x959bb2ff).into(), + text_placeholder: rgba(0xc94922ff).into(), + text_disabled: rgba(0x7e849eff).into(), + text_accent: rgba(0x3e8ed0ff).into(), + icon_muted: rgba(0x959bb2ff).into(), + syntax: SyntaxTheme { + highlights: vec![ + ("title".into(), rgba(0xf5f7ffff).into()), + ("constructor".into(), rgba(0x3e8ed0ff).into()), + ("type".into(), rgba(0xc08b2fff).into()), + ("punctuation.list_marker".into(), rgba(0xdfe2f1ff).into()), + ("property".into(), rgba(0xc94821ff).into()), + ("link_uri".into(), rgba(0xac9739ff).into()), + ("string.escape".into(), rgba(0x979db4ff).into()), + ("constant".into(), rgba(0xac9739ff).into()), + ("embedded".into(), rgba(0xf5f7ffff).into()), + ("punctuation.special".into(), rgba(0x9b6279ff).into()), + ("punctuation.bracket".into(), rgba(0x979db4ff).into()), + ("preproc".into(), rgba(0xf5f7ffff).into()), + ("emphasis.strong".into(), rgba(0x3e8ed0ff).into()), + ("emphasis".into(), rgba(0x3e8ed0ff).into()), + ("enum".into(), rgba(0xc76a29ff).into()), + ("boolean".into(), rgba(0xac9739ff).into()), + ("primary".into(), rgba(0xdfe2f1ff).into()), + ("function.method".into(), rgba(0x3d8fd1ff).into()), + ( + "function.special.definition".into(), + rgba(0xc08b2fff).into(), + ), + ("comment.doc".into(), rgba(0x979db4ff).into()), + ("string".into(), rgba(0xac9738ff).into()), + ("text.literal".into(), rgba(0xc76a29ff).into()), + ("operator".into(), rgba(0x979db4ff).into()), + ("number".into(), rgba(0xc76a28ff).into()), + ("string.special".into(), rgba(0x9b6279ff).into()), + ("punctuation.delimiter".into(), rgba(0x979db4ff).into()), + ("tag".into(), rgba(0x3e8ed0ff).into()), + ("string.special.symbol".into(), rgba(0xac9738ff).into()), + ("variable".into(), rgba(0xdfe2f1ff).into()), + ("attribute".into(), rgba(0x3e8ed0ff).into()), + ("punctuation".into(), rgba(0xdfe2f1ff).into()), + ("string.regex".into(), rgba(0x21a2c9ff).into()), + ("keyword".into(), rgba(0x6679ccff).into()), + ("label".into(), rgba(0x3e8ed0ff).into()), + ("hint".into(), rgba(0x6c81a5ff).into()), + ("function".into(), rgba(0x3d8fd1ff).into()), + ("link_text".into(), rgba(0xc76a29ff).into()), + ("variant".into(), rgba(0xc08b2fff).into()), + ("variable.special".into(), rgba(0x6679ccff).into()), + ("predictive".into(), rgba(0x58709aff).into()), + ("comment".into(), rgba(0x6a7293ff).into()), + ], + }, + status_bar: rgba(0x3e4769ff).into(), + title_bar: rgba(0x3e4769ff).into(), + toolbar: rgba(0x202646ff).into(), + tab_bar: rgba(0x262f51ff).into(), + editor: rgba(0x202646ff).into(), + editor_subheader: rgba(0x262f51ff).into(), + editor_active_line: rgba(0x262f51ff).into(), + terminal: rgba(0x202646ff).into(), + image_fallback_background: rgba(0x3e4769ff).into(), + git_created: rgba(0xac9739ff).into(), + git_modified: rgba(0x3e8ed0ff).into(), + git_deleted: rgba(0xc94922ff).into(), + git_conflict: rgba(0xc08b30ff).into(), + git_ignored: rgba(0x7e849eff).into(), + git_renamed: rgba(0xc08b30ff).into(), + players: [ + PlayerTheme { + cursor: rgba(0x3e8ed0ff).into(), + selection: rgba(0x3e8ed03d).into(), + }, + PlayerTheme { + cursor: rgba(0xac9739ff).into(), + selection: rgba(0xac97393d).into(), + }, + PlayerTheme { + cursor: rgba(0x9b6279ff).into(), + selection: rgba(0x9b62793d).into(), + }, + PlayerTheme { + cursor: rgba(0xc76a29ff).into(), + selection: rgba(0xc76a293d).into(), + }, + PlayerTheme { + cursor: rgba(0x6679ccff).into(), + selection: rgba(0x6679cc3d).into(), + }, + PlayerTheme { + cursor: rgba(0x24a1c9ff).into(), + selection: rgba(0x24a1c93d).into(), + }, + PlayerTheme { + cursor: rgba(0xc94922ff).into(), + selection: rgba(0xc949223d).into(), + }, + PlayerTheme { + cursor: rgba(0xc08b30ff).into(), + selection: rgba(0xc08b303d).into(), + }, + ], + } +} diff --git a/crates/theme2/src/themes/atelier_sulphurpool_light.rs b/crates/theme2/src/themes/atelier_sulphurpool_light.rs new file mode 100644 index 0000000000..dba723331a --- /dev/null +++ b/crates/theme2/src/themes/atelier_sulphurpool_light.rs @@ -0,0 +1,136 @@ +use gpui2::rgba; + +use crate::{PlayerTheme, SyntaxTheme, Theme, ThemeMetadata}; + +pub fn atelier_sulphurpool_light() -> Theme { + Theme { + metadata: ThemeMetadata { + name: "Atelier Sulphurpool Light".into(), + is_light: true, + }, + transparent: rgba(0x00000000).into(), + mac_os_traffic_light_red: rgba(0xec695eff).into(), + mac_os_traffic_light_yellow: rgba(0xf4bf4eff).into(), + mac_os_traffic_light_green: rgba(0x61c553ff).into(), + border: rgba(0x9a9fb6ff).into(), + border_variant: rgba(0x9a9fb6ff).into(), + border_focused: rgba(0xc2d5efff).into(), + border_transparent: rgba(0x00000000).into(), + elevated_surface: rgba(0xc1c5d8ff).into(), + surface: rgba(0xe5e8f5ff).into(), + background: rgba(0xc1c5d8ff).into(), + filled_element: rgba(0xc1c5d8ff).into(), + filled_element_hover: rgba(0xffffff1e).into(), + filled_element_active: rgba(0xffffff28).into(), + filled_element_selected: rgba(0xdde7f6ff).into(), + filled_element_disabled: rgba(0x00000000).into(), + ghost_element: rgba(0x00000000).into(), + ghost_element_hover: rgba(0xffffff14).into(), + ghost_element_active: rgba(0xffffff1e).into(), + ghost_element_selected: rgba(0xdde7f6ff).into(), + ghost_element_disabled: rgba(0x00000000).into(), + text: rgba(0x202646ff).into(), + text_muted: rgba(0x5f6789ff).into(), + text_placeholder: rgba(0xc94922ff).into(), + text_disabled: rgba(0x767d9aff).into(), + text_accent: rgba(0x3e8fd0ff).into(), + icon_muted: rgba(0x5f6789ff).into(), + syntax: SyntaxTheme { + highlights: vec![ + ("string.special".into(), rgba(0x9b6279ff).into()), + ("string.regex".into(), rgba(0x21a2c9ff).into()), + ("embedded".into(), rgba(0x202646ff).into()), + ("string".into(), rgba(0xac9738ff).into()), + ( + "function.special.definition".into(), + rgba(0xc08b2fff).into(), + ), + ("hint".into(), rgba(0x7087b2ff).into()), + ("function.method".into(), rgba(0x3d8fd1ff).into()), + ("punctuation.list_marker".into(), rgba(0x293256ff).into()), + ("punctuation".into(), rgba(0x293256ff).into()), + ("constant".into(), rgba(0xac9739ff).into()), + ("label".into(), rgba(0x3e8fd0ff).into()), + ("comment.doc".into(), rgba(0x5d6587ff).into()), + ("property".into(), rgba(0xc94821ff).into()), + ("punctuation.bracket".into(), rgba(0x5d6587ff).into()), + ("constructor".into(), rgba(0x3e8fd0ff).into()), + ("variable.special".into(), rgba(0x6679ccff).into()), + ("emphasis".into(), rgba(0x3e8fd0ff).into()), + ("link_text".into(), rgba(0xc76a29ff).into()), + ("keyword".into(), rgba(0x6679ccff).into()), + ("primary".into(), rgba(0x293256ff).into()), + ("comment".into(), rgba(0x898ea4ff).into()), + ("title".into(), rgba(0x202646ff).into()), + ("link_uri".into(), rgba(0xac9739ff).into()), + ("text.literal".into(), rgba(0xc76a29ff).into()), + ("operator".into(), rgba(0x5d6587ff).into()), + ("number".into(), rgba(0xc76a28ff).into()), + ("preproc".into(), rgba(0x202646ff).into()), + ("attribute".into(), rgba(0x3e8fd0ff).into()), + ("emphasis.strong".into(), rgba(0x3e8fd0ff).into()), + ("string.escape".into(), rgba(0x5d6587ff).into()), + ("tag".into(), rgba(0x3e8fd0ff).into()), + ("variable".into(), rgba(0x293256ff).into()), + ("predictive".into(), rgba(0x8599beff).into()), + ("enum".into(), rgba(0xc76a29ff).into()), + ("string.special.symbol".into(), rgba(0xac9738ff).into()), + ("punctuation.delimiter".into(), rgba(0x5d6587ff).into()), + ("function".into(), rgba(0x3d8fd1ff).into()), + ("type".into(), rgba(0xc08b2fff).into()), + ("punctuation.special".into(), rgba(0x9b6279ff).into()), + ("variant".into(), rgba(0xc08b2fff).into()), + ("boolean".into(), rgba(0xac9739ff).into()), + ], + }, + status_bar: rgba(0xc1c5d8ff).into(), + title_bar: rgba(0xc1c5d8ff).into(), + toolbar: rgba(0xf5f7ffff).into(), + tab_bar: rgba(0xe5e8f5ff).into(), + editor: rgba(0xf5f7ffff).into(), + editor_subheader: rgba(0xe5e8f5ff).into(), + editor_active_line: rgba(0xe5e8f5ff).into(), + terminal: rgba(0xf5f7ffff).into(), + image_fallback_background: rgba(0xc1c5d8ff).into(), + git_created: rgba(0xac9739ff).into(), + git_modified: rgba(0x3e8fd0ff).into(), + git_deleted: rgba(0xc94922ff).into(), + git_conflict: rgba(0xc08b30ff).into(), + git_ignored: rgba(0x767d9aff).into(), + git_renamed: rgba(0xc08b30ff).into(), + players: [ + PlayerTheme { + cursor: rgba(0x3e8fd0ff).into(), + selection: rgba(0x3e8fd03d).into(), + }, + PlayerTheme { + cursor: rgba(0xac9739ff).into(), + selection: rgba(0xac97393d).into(), + }, + PlayerTheme { + cursor: rgba(0x9b6279ff).into(), + selection: rgba(0x9b62793d).into(), + }, + PlayerTheme { + cursor: rgba(0xc76a29ff).into(), + selection: rgba(0xc76a293d).into(), + }, + PlayerTheme { + cursor: rgba(0x6679cbff).into(), + selection: rgba(0x6679cb3d).into(), + }, + PlayerTheme { + cursor: rgba(0x24a1c9ff).into(), + selection: rgba(0x24a1c93d).into(), + }, + PlayerTheme { + cursor: rgba(0xc94922ff).into(), + selection: rgba(0xc949223d).into(), + }, + PlayerTheme { + cursor: rgba(0xc08b30ff).into(), + selection: rgba(0xc08b303d).into(), + }, + ], + } +} diff --git a/crates/theme2/src/themes/ayu_dark.rs b/crates/theme2/src/themes/ayu_dark.rs new file mode 100644 index 0000000000..35d3a43154 --- /dev/null +++ b/crates/theme2/src/themes/ayu_dark.rs @@ -0,0 +1,130 @@ +use gpui2::rgba; + +use crate::{PlayerTheme, SyntaxTheme, Theme, ThemeMetadata}; + +pub fn ayu_dark() -> Theme { + Theme { + metadata: ThemeMetadata { + name: "Ayu Dark".into(), + is_light: false, + }, + transparent: rgba(0x00000000).into(), + mac_os_traffic_light_red: rgba(0xec695eff).into(), + mac_os_traffic_light_yellow: rgba(0xf4bf4eff).into(), + mac_os_traffic_light_green: rgba(0x61c553ff).into(), + border: rgba(0x3f4043ff).into(), + border_variant: rgba(0x3f4043ff).into(), + border_focused: rgba(0x1b4a6eff).into(), + border_transparent: rgba(0x00000000).into(), + elevated_surface: rgba(0x313337ff).into(), + surface: rgba(0x1f2127ff).into(), + background: rgba(0x313337ff).into(), + filled_element: rgba(0x313337ff).into(), + filled_element_hover: rgba(0xffffff1e).into(), + filled_element_active: rgba(0xffffff28).into(), + filled_element_selected: rgba(0x0d2f4eff).into(), + filled_element_disabled: rgba(0x00000000).into(), + ghost_element: rgba(0x00000000).into(), + ghost_element_hover: rgba(0xffffff14).into(), + ghost_element_active: rgba(0xffffff1e).into(), + ghost_element_selected: rgba(0x0d2f4eff).into(), + ghost_element_disabled: rgba(0x00000000).into(), + text: rgba(0xbfbdb6ff).into(), + text_muted: rgba(0x8a8986ff).into(), + text_placeholder: rgba(0xef7177ff).into(), + text_disabled: rgba(0x696a6aff).into(), + text_accent: rgba(0x5ac1feff).into(), + icon_muted: rgba(0x8a8986ff).into(), + syntax: SyntaxTheme { + highlights: vec![ + ("emphasis".into(), rgba(0x5ac1feff).into()), + ("punctuation.bracket".into(), rgba(0xa6a5a0ff).into()), + ("constructor".into(), rgba(0x5ac1feff).into()), + ("predictive".into(), rgba(0x5a728bff).into()), + ("emphasis.strong".into(), rgba(0x5ac1feff).into()), + ("string.regex".into(), rgba(0x95e6cbff).into()), + ("tag".into(), rgba(0x5ac1feff).into()), + ("punctuation".into(), rgba(0xa6a5a0ff).into()), + ("number".into(), rgba(0xd2a6ffff).into()), + ("punctuation.special".into(), rgba(0xd2a6ffff).into()), + ("primary".into(), rgba(0xbfbdb6ff).into()), + ("boolean".into(), rgba(0xd2a6ffff).into()), + ("variant".into(), rgba(0x5ac1feff).into()), + ("link_uri".into(), rgba(0xaad84cff).into()), + ("comment.doc".into(), rgba(0x8c8b88ff).into()), + ("title".into(), rgba(0xbfbdb6ff).into()), + ("text.literal".into(), rgba(0xfe8f40ff).into()), + ("link_text".into(), rgba(0xfe8f40ff).into()), + ("punctuation.delimiter".into(), rgba(0xa6a5a0ff).into()), + ("string.escape".into(), rgba(0x8c8b88ff).into()), + ("hint".into(), rgba(0x628b80ff).into()), + ("type".into(), rgba(0x59c2ffff).into()), + ("variable".into(), rgba(0xbfbdb6ff).into()), + ("label".into(), rgba(0x5ac1feff).into()), + ("enum".into(), rgba(0xfe8f40ff).into()), + ("operator".into(), rgba(0xf29668ff).into()), + ("function".into(), rgba(0xffb353ff).into()), + ("preproc".into(), rgba(0xbfbdb6ff).into()), + ("embedded".into(), rgba(0xbfbdb6ff).into()), + ("string".into(), rgba(0xa9d94bff).into()), + ("attribute".into(), rgba(0x5ac1feff).into()), + ("keyword".into(), rgba(0xff8f3fff).into()), + ("string.special.symbol".into(), rgba(0xfe8f40ff).into()), + ("comment".into(), rgba(0xabb5be8c).into()), + ("property".into(), rgba(0x5ac1feff).into()), + ("punctuation.list_marker".into(), rgba(0xa6a5a0ff).into()), + ("constant".into(), rgba(0xd2a6ffff).into()), + ("string.special".into(), rgba(0xe5b572ff).into()), + ], + }, + status_bar: rgba(0x313337ff).into(), + title_bar: rgba(0x313337ff).into(), + toolbar: rgba(0x0d1016ff).into(), + tab_bar: rgba(0x1f2127ff).into(), + editor: rgba(0x0d1016ff).into(), + editor_subheader: rgba(0x1f2127ff).into(), + editor_active_line: rgba(0x1f2127ff).into(), + terminal: rgba(0x0d1016ff).into(), + image_fallback_background: rgba(0x313337ff).into(), + git_created: rgba(0xaad84cff).into(), + git_modified: rgba(0x5ac1feff).into(), + git_deleted: rgba(0xef7177ff).into(), + git_conflict: rgba(0xfeb454ff).into(), + git_ignored: rgba(0x696a6aff).into(), + git_renamed: rgba(0xfeb454ff).into(), + players: [ + PlayerTheme { + cursor: rgba(0x5ac1feff).into(), + selection: rgba(0x5ac1fe3d).into(), + }, + PlayerTheme { + cursor: rgba(0xaad84cff).into(), + selection: rgba(0xaad84c3d).into(), + }, + PlayerTheme { + cursor: rgba(0x39bae5ff).into(), + selection: rgba(0x39bae53d).into(), + }, + PlayerTheme { + cursor: rgba(0xfe8f40ff).into(), + selection: rgba(0xfe8f403d).into(), + }, + PlayerTheme { + cursor: rgba(0xd2a6feff).into(), + selection: rgba(0xd2a6fe3d).into(), + }, + PlayerTheme { + cursor: rgba(0x95e5cbff).into(), + selection: rgba(0x95e5cb3d).into(), + }, + PlayerTheme { + cursor: rgba(0xef7177ff).into(), + selection: rgba(0xef71773d).into(), + }, + PlayerTheme { + cursor: rgba(0xfeb454ff).into(), + selection: rgba(0xfeb4543d).into(), + }, + ], + } +} diff --git a/crates/theme2/src/themes/ayu_light.rs b/crates/theme2/src/themes/ayu_light.rs new file mode 100644 index 0000000000..887282e564 --- /dev/null +++ b/crates/theme2/src/themes/ayu_light.rs @@ -0,0 +1,130 @@ +use gpui2::rgba; + +use crate::{PlayerTheme, SyntaxTheme, Theme, ThemeMetadata}; + +pub fn ayu_light() -> Theme { + Theme { + metadata: ThemeMetadata { + name: "Ayu Light".into(), + is_light: true, + }, + transparent: rgba(0x00000000).into(), + mac_os_traffic_light_red: rgba(0xec695eff).into(), + mac_os_traffic_light_yellow: rgba(0xf4bf4eff).into(), + mac_os_traffic_light_green: rgba(0x61c553ff).into(), + border: rgba(0xcfd1d2ff).into(), + border_variant: rgba(0xcfd1d2ff).into(), + border_focused: rgba(0xc4daf6ff).into(), + border_transparent: rgba(0x00000000).into(), + elevated_surface: rgba(0xdcdddeff).into(), + surface: rgba(0xececedff).into(), + background: rgba(0xdcdddeff).into(), + filled_element: rgba(0xdcdddeff).into(), + filled_element_hover: rgba(0xffffff1e).into(), + filled_element_active: rgba(0xffffff28).into(), + filled_element_selected: rgba(0xdeebfaff).into(), + filled_element_disabled: rgba(0x00000000).into(), + ghost_element: rgba(0x00000000).into(), + ghost_element_hover: rgba(0xffffff14).into(), + ghost_element_active: rgba(0xffffff1e).into(), + ghost_element_selected: rgba(0xdeebfaff).into(), + ghost_element_disabled: rgba(0x00000000).into(), + text: rgba(0x5c6166ff).into(), + text_muted: rgba(0x8b8e92ff).into(), + text_placeholder: rgba(0xef7271ff).into(), + text_disabled: rgba(0xa9acaeff).into(), + text_accent: rgba(0x3b9ee5ff).into(), + icon_muted: rgba(0x8b8e92ff).into(), + syntax: SyntaxTheme { + highlights: vec![ + ("string".into(), rgba(0x86b300ff).into()), + ("enum".into(), rgba(0xf98d3fff).into()), + ("comment".into(), rgba(0x787b8099).into()), + ("comment.doc".into(), rgba(0x898d90ff).into()), + ("emphasis".into(), rgba(0x3b9ee5ff).into()), + ("keyword".into(), rgba(0xfa8d3eff).into()), + ("string.regex".into(), rgba(0x4bbf98ff).into()), + ("text.literal".into(), rgba(0xf98d3fff).into()), + ("string.escape".into(), rgba(0x898d90ff).into()), + ("link_text".into(), rgba(0xf98d3fff).into()), + ("punctuation".into(), rgba(0x73777bff).into()), + ("constructor".into(), rgba(0x3b9ee5ff).into()), + ("constant".into(), rgba(0xa37accff).into()), + ("variable".into(), rgba(0x5c6166ff).into()), + ("primary".into(), rgba(0x5c6166ff).into()), + ("emphasis.strong".into(), rgba(0x3b9ee5ff).into()), + ("string.special".into(), rgba(0xe6ba7eff).into()), + ("number".into(), rgba(0xa37accff).into()), + ("preproc".into(), rgba(0x5c6166ff).into()), + ("punctuation.delimiter".into(), rgba(0x73777bff).into()), + ("string.special.symbol".into(), rgba(0xf98d3fff).into()), + ("boolean".into(), rgba(0xa37accff).into()), + ("property".into(), rgba(0x3b9ee5ff).into()), + ("title".into(), rgba(0x5c6166ff).into()), + ("hint".into(), rgba(0x8ca7c2ff).into()), + ("predictive".into(), rgba(0x9eb9d3ff).into()), + ("operator".into(), rgba(0xed9365ff).into()), + ("type".into(), rgba(0x389ee6ff).into()), + ("function".into(), rgba(0xf2ad48ff).into()), + ("variant".into(), rgba(0x3b9ee5ff).into()), + ("label".into(), rgba(0x3b9ee5ff).into()), + ("punctuation.list_marker".into(), rgba(0x73777bff).into()), + ("punctuation.bracket".into(), rgba(0x73777bff).into()), + ("embedded".into(), rgba(0x5c6166ff).into()), + ("punctuation.special".into(), rgba(0xa37accff).into()), + ("attribute".into(), rgba(0x3b9ee5ff).into()), + ("tag".into(), rgba(0x3b9ee5ff).into()), + ("link_uri".into(), rgba(0x85b304ff).into()), + ], + }, + status_bar: rgba(0xdcdddeff).into(), + title_bar: rgba(0xdcdddeff).into(), + toolbar: rgba(0xfcfcfcff).into(), + tab_bar: rgba(0xececedff).into(), + editor: rgba(0xfcfcfcff).into(), + editor_subheader: rgba(0xececedff).into(), + editor_active_line: rgba(0xececedff).into(), + terminal: rgba(0xfcfcfcff).into(), + image_fallback_background: rgba(0xdcdddeff).into(), + git_created: rgba(0x85b304ff).into(), + git_modified: rgba(0x3b9ee5ff).into(), + git_deleted: rgba(0xef7271ff).into(), + git_conflict: rgba(0xf1ad49ff).into(), + git_ignored: rgba(0xa9acaeff).into(), + git_renamed: rgba(0xf1ad49ff).into(), + players: [ + PlayerTheme { + cursor: rgba(0x3b9ee5ff).into(), + selection: rgba(0x3b9ee53d).into(), + }, + PlayerTheme { + cursor: rgba(0x85b304ff).into(), + selection: rgba(0x85b3043d).into(), + }, + PlayerTheme { + cursor: rgba(0x55b4d3ff).into(), + selection: rgba(0x55b4d33d).into(), + }, + PlayerTheme { + cursor: rgba(0xf98d3fff).into(), + selection: rgba(0xf98d3f3d).into(), + }, + PlayerTheme { + cursor: rgba(0xa37accff).into(), + selection: rgba(0xa37acc3d).into(), + }, + PlayerTheme { + cursor: rgba(0x4dbf99ff).into(), + selection: rgba(0x4dbf993d).into(), + }, + PlayerTheme { + cursor: rgba(0xef7271ff).into(), + selection: rgba(0xef72713d).into(), + }, + PlayerTheme { + cursor: rgba(0xf1ad49ff).into(), + selection: rgba(0xf1ad493d).into(), + }, + ], + } +} diff --git a/crates/theme2/src/themes/ayu_mirage.rs b/crates/theme2/src/themes/ayu_mirage.rs new file mode 100644 index 0000000000..2974881a18 --- /dev/null +++ b/crates/theme2/src/themes/ayu_mirage.rs @@ -0,0 +1,130 @@ +use gpui2::rgba; + +use crate::{PlayerTheme, SyntaxTheme, Theme, ThemeMetadata}; + +pub fn ayu_mirage() -> Theme { + Theme { + metadata: ThemeMetadata { + name: "Ayu Mirage".into(), + is_light: false, + }, + transparent: rgba(0x00000000).into(), + mac_os_traffic_light_red: rgba(0xec695eff).into(), + mac_os_traffic_light_yellow: rgba(0xf4bf4eff).into(), + mac_os_traffic_light_green: rgba(0x61c553ff).into(), + border: rgba(0x53565dff).into(), + border_variant: rgba(0x53565dff).into(), + border_focused: rgba(0x24556fff).into(), + border_transparent: rgba(0x00000000).into(), + elevated_surface: rgba(0x464a52ff).into(), + surface: rgba(0x353944ff).into(), + background: rgba(0x464a52ff).into(), + filled_element: rgba(0x464a52ff).into(), + filled_element_hover: rgba(0xffffff1e).into(), + filled_element_active: rgba(0xffffff28).into(), + filled_element_selected: rgba(0x123950ff).into(), + filled_element_disabled: rgba(0x00000000).into(), + ghost_element: rgba(0x00000000).into(), + ghost_element_hover: rgba(0xffffff14).into(), + ghost_element_active: rgba(0xffffff1e).into(), + ghost_element_selected: rgba(0x123950ff).into(), + ghost_element_disabled: rgba(0x00000000).into(), + text: rgba(0xcccac2ff).into(), + text_muted: rgba(0x9a9a98ff).into(), + text_placeholder: rgba(0xf18779ff).into(), + text_disabled: rgba(0x7b7d7fff).into(), + text_accent: rgba(0x72cffeff).into(), + icon_muted: rgba(0x9a9a98ff).into(), + syntax: SyntaxTheme { + highlights: vec![ + ("text.literal".into(), rgba(0xfead66ff).into()), + ("link_text".into(), rgba(0xfead66ff).into()), + ("function".into(), rgba(0xffd173ff).into()), + ("punctuation.delimiter".into(), rgba(0xb4b3aeff).into()), + ("property".into(), rgba(0x72cffeff).into()), + ("title".into(), rgba(0xcccac2ff).into()), + ("boolean".into(), rgba(0xdfbfffff).into()), + ("link_uri".into(), rgba(0xd5fe80ff).into()), + ("label".into(), rgba(0x72cffeff).into()), + ("primary".into(), rgba(0xcccac2ff).into()), + ("number".into(), rgba(0xdfbfffff).into()), + ("variant".into(), rgba(0x72cffeff).into()), + ("enum".into(), rgba(0xfead66ff).into()), + ("string.special.symbol".into(), rgba(0xfead66ff).into()), + ("operator".into(), rgba(0xf29e74ff).into()), + ("punctuation.special".into(), rgba(0xdfbfffff).into()), + ("constructor".into(), rgba(0x72cffeff).into()), + ("type".into(), rgba(0x73cfffff).into()), + ("emphasis.strong".into(), rgba(0x72cffeff).into()), + ("embedded".into(), rgba(0xcccac2ff).into()), + ("comment".into(), rgba(0xb8cfe680).into()), + ("tag".into(), rgba(0x72cffeff).into()), + ("keyword".into(), rgba(0xffad65ff).into()), + ("punctuation".into(), rgba(0xb4b3aeff).into()), + ("preproc".into(), rgba(0xcccac2ff).into()), + ("hint".into(), rgba(0x7399a3ff).into()), + ("string.special".into(), rgba(0xffdfb3ff).into()), + ("attribute".into(), rgba(0x72cffeff).into()), + ("string.regex".into(), rgba(0x95e6cbff).into()), + ("predictive".into(), rgba(0x6d839bff).into()), + ("comment.doc".into(), rgba(0x9b9b99ff).into()), + ("emphasis".into(), rgba(0x72cffeff).into()), + ("string".into(), rgba(0xd4fe7fff).into()), + ("constant".into(), rgba(0xdfbfffff).into()), + ("string.escape".into(), rgba(0x9b9b99ff).into()), + ("variable".into(), rgba(0xcccac2ff).into()), + ("punctuation.bracket".into(), rgba(0xb4b3aeff).into()), + ("punctuation.list_marker".into(), rgba(0xb4b3aeff).into()), + ], + }, + status_bar: rgba(0x464a52ff).into(), + title_bar: rgba(0x464a52ff).into(), + toolbar: rgba(0x242835ff).into(), + tab_bar: rgba(0x353944ff).into(), + editor: rgba(0x242835ff).into(), + editor_subheader: rgba(0x353944ff).into(), + editor_active_line: rgba(0x353944ff).into(), + terminal: rgba(0x242835ff).into(), + image_fallback_background: rgba(0x464a52ff).into(), + git_created: rgba(0xd5fe80ff).into(), + git_modified: rgba(0x72cffeff).into(), + git_deleted: rgba(0xf18779ff).into(), + git_conflict: rgba(0xfecf72ff).into(), + git_ignored: rgba(0x7b7d7fff).into(), + git_renamed: rgba(0xfecf72ff).into(), + players: [ + PlayerTheme { + cursor: rgba(0x72cffeff).into(), + selection: rgba(0x72cffe3d).into(), + }, + PlayerTheme { + cursor: rgba(0xd5fe80ff).into(), + selection: rgba(0xd5fe803d).into(), + }, + PlayerTheme { + cursor: rgba(0x5bcde5ff).into(), + selection: rgba(0x5bcde53d).into(), + }, + PlayerTheme { + cursor: rgba(0xfead66ff).into(), + selection: rgba(0xfead663d).into(), + }, + PlayerTheme { + cursor: rgba(0xdebffeff).into(), + selection: rgba(0xdebffe3d).into(), + }, + PlayerTheme { + cursor: rgba(0x95e5cbff).into(), + selection: rgba(0x95e5cb3d).into(), + }, + PlayerTheme { + cursor: rgba(0xf18779ff).into(), + selection: rgba(0xf187793d).into(), + }, + PlayerTheme { + cursor: rgba(0xfecf72ff).into(), + selection: rgba(0xfecf723d).into(), + }, + ], + } +} diff --git a/crates/theme2/src/themes/gruvbox_dark.rs b/crates/theme2/src/themes/gruvbox_dark.rs new file mode 100644 index 0000000000..6e982808cf --- /dev/null +++ b/crates/theme2/src/themes/gruvbox_dark.rs @@ -0,0 +1,131 @@ +use gpui2::rgba; + +use crate::{PlayerTheme, SyntaxTheme, Theme, ThemeMetadata}; + +pub fn gruvbox_dark() -> Theme { + Theme { + metadata: ThemeMetadata { + name: "Gruvbox Dark".into(), + is_light: false, + }, + transparent: rgba(0x00000000).into(), + mac_os_traffic_light_red: rgba(0xec695eff).into(), + mac_os_traffic_light_yellow: rgba(0xf4bf4eff).into(), + mac_os_traffic_light_green: rgba(0x61c553ff).into(), + border: rgba(0x5b534dff).into(), + border_variant: rgba(0x5b534dff).into(), + border_focused: rgba(0x303a36ff).into(), + border_transparent: rgba(0x00000000).into(), + elevated_surface: rgba(0x4c4642ff).into(), + surface: rgba(0x3a3735ff).into(), + background: rgba(0x4c4642ff).into(), + filled_element: rgba(0x4c4642ff).into(), + filled_element_hover: rgba(0xffffff1e).into(), + filled_element_active: rgba(0xffffff28).into(), + filled_element_selected: rgba(0x1e2321ff).into(), + filled_element_disabled: rgba(0x00000000).into(), + ghost_element: rgba(0x00000000).into(), + ghost_element_hover: rgba(0xffffff14).into(), + ghost_element_active: rgba(0xffffff1e).into(), + ghost_element_selected: rgba(0x1e2321ff).into(), + ghost_element_disabled: rgba(0x00000000).into(), + text: rgba(0xfbf1c7ff).into(), + text_muted: rgba(0xc5b597ff).into(), + text_placeholder: rgba(0xfb4a35ff).into(), + text_disabled: rgba(0x998b78ff).into(), + text_accent: rgba(0x83a598ff).into(), + icon_muted: rgba(0xc5b597ff).into(), + syntax: SyntaxTheme { + highlights: vec![ + ("operator".into(), rgba(0x8ec07cff).into()), + ("string.special.symbol".into(), rgba(0x8ec07cff).into()), + ("emphasis.strong".into(), rgba(0x83a598ff).into()), + ("attribute".into(), rgba(0x83a598ff).into()), + ("property".into(), rgba(0xebdbb2ff).into()), + ("comment.doc".into(), rgba(0xc6b697ff).into()), + ("emphasis".into(), rgba(0x83a598ff).into()), + ("variant".into(), rgba(0x83a598ff).into()), + ("text.literal".into(), rgba(0x83a598ff).into()), + ("keyword".into(), rgba(0xfb4833ff).into()), + ("primary".into(), rgba(0xebdbb2ff).into()), + ("variable".into(), rgba(0x83a598ff).into()), + ("enum".into(), rgba(0xfe7f18ff).into()), + ("constructor".into(), rgba(0x83a598ff).into()), + ("punctuation".into(), rgba(0xd5c4a1ff).into()), + ("link_uri".into(), rgba(0xd3869bff).into()), + ("hint".into(), rgba(0x8c957dff).into()), + ("string.regex".into(), rgba(0xfe7f18ff).into()), + ("punctuation.delimiter".into(), rgba(0xe5d5adff).into()), + ("string".into(), rgba(0xb8bb25ff).into()), + ("punctuation.special".into(), rgba(0xe5d5adff).into()), + ("link_text".into(), rgba(0x8ec07cff).into()), + ("tag".into(), rgba(0x8ec07cff).into()), + ("string.escape".into(), rgba(0xc6b697ff).into()), + ("label".into(), rgba(0x83a598ff).into()), + ("constant".into(), rgba(0xfabd2eff).into()), + ("type".into(), rgba(0xfabd2eff).into()), + ("number".into(), rgba(0xd3869bff).into()), + ("string.special".into(), rgba(0xd3869bff).into()), + ("function.builtin".into(), rgba(0xfb4833ff).into()), + ("boolean".into(), rgba(0xd3869bff).into()), + ("embedded".into(), rgba(0x8ec07cff).into()), + ("title".into(), rgba(0xb8bb25ff).into()), + ("function".into(), rgba(0xb8bb25ff).into()), + ("punctuation.bracket".into(), rgba(0xa89984ff).into()), + ("comment".into(), rgba(0xa89984ff).into()), + ("preproc".into(), rgba(0xfbf1c7ff).into()), + ("predictive".into(), rgba(0x717363ff).into()), + ("punctuation.list_marker".into(), rgba(0xebdbb2ff).into()), + ], + }, + status_bar: rgba(0x4c4642ff).into(), + title_bar: rgba(0x4c4642ff).into(), + toolbar: rgba(0x282828ff).into(), + tab_bar: rgba(0x3a3735ff).into(), + editor: rgba(0x282828ff).into(), + editor_subheader: rgba(0x3a3735ff).into(), + editor_active_line: rgba(0x3a3735ff).into(), + terminal: rgba(0x282828ff).into(), + image_fallback_background: rgba(0x4c4642ff).into(), + git_created: rgba(0xb7bb26ff).into(), + git_modified: rgba(0x83a598ff).into(), + git_deleted: rgba(0xfb4a35ff).into(), + git_conflict: rgba(0xf9bd2fff).into(), + git_ignored: rgba(0x998b78ff).into(), + git_renamed: rgba(0xf9bd2fff).into(), + players: [ + PlayerTheme { + cursor: rgba(0x83a598ff).into(), + selection: rgba(0x83a5983d).into(), + }, + PlayerTheme { + cursor: rgba(0xb7bb26ff).into(), + selection: rgba(0xb7bb263d).into(), + }, + PlayerTheme { + cursor: rgba(0xa89984ff).into(), + selection: rgba(0xa899843d).into(), + }, + PlayerTheme { + cursor: rgba(0xfd801bff).into(), + selection: rgba(0xfd801b3d).into(), + }, + PlayerTheme { + cursor: rgba(0xd3869bff).into(), + selection: rgba(0xd3869b3d).into(), + }, + PlayerTheme { + cursor: rgba(0x8ec07cff).into(), + selection: rgba(0x8ec07c3d).into(), + }, + PlayerTheme { + cursor: rgba(0xfb4a35ff).into(), + selection: rgba(0xfb4a353d).into(), + }, + PlayerTheme { + cursor: rgba(0xf9bd2fff).into(), + selection: rgba(0xf9bd2f3d).into(), + }, + ], + } +} diff --git a/crates/theme2/src/themes/gruvbox_dark_hard.rs b/crates/theme2/src/themes/gruvbox_dark_hard.rs new file mode 100644 index 0000000000..159ab28325 --- /dev/null +++ b/crates/theme2/src/themes/gruvbox_dark_hard.rs @@ -0,0 +1,131 @@ +use gpui2::rgba; + +use crate::{PlayerTheme, SyntaxTheme, Theme, ThemeMetadata}; + +pub fn gruvbox_dark_hard() -> Theme { + Theme { + metadata: ThemeMetadata { + name: "Gruvbox Dark Hard".into(), + is_light: false, + }, + transparent: rgba(0x00000000).into(), + mac_os_traffic_light_red: rgba(0xec695eff).into(), + mac_os_traffic_light_yellow: rgba(0xf4bf4eff).into(), + mac_os_traffic_light_green: rgba(0x61c553ff).into(), + border: rgba(0x5b534dff).into(), + border_variant: rgba(0x5b534dff).into(), + border_focused: rgba(0x303a36ff).into(), + border_transparent: rgba(0x00000000).into(), + elevated_surface: rgba(0x4c4642ff).into(), + surface: rgba(0x393634ff).into(), + background: rgba(0x4c4642ff).into(), + filled_element: rgba(0x4c4642ff).into(), + filled_element_hover: rgba(0xffffff1e).into(), + filled_element_active: rgba(0xffffff28).into(), + filled_element_selected: rgba(0x1e2321ff).into(), + filled_element_disabled: rgba(0x00000000).into(), + ghost_element: rgba(0x00000000).into(), + ghost_element_hover: rgba(0xffffff14).into(), + ghost_element_active: rgba(0xffffff1e).into(), + ghost_element_selected: rgba(0x1e2321ff).into(), + ghost_element_disabled: rgba(0x00000000).into(), + text: rgba(0xfbf1c7ff).into(), + text_muted: rgba(0xc5b597ff).into(), + text_placeholder: rgba(0xfb4a35ff).into(), + text_disabled: rgba(0x998b78ff).into(), + text_accent: rgba(0x83a598ff).into(), + icon_muted: rgba(0xc5b597ff).into(), + syntax: SyntaxTheme { + highlights: vec![ + ("primary".into(), rgba(0xebdbb2ff).into()), + ("label".into(), rgba(0x83a598ff).into()), + ("punctuation.delimiter".into(), rgba(0xe5d5adff).into()), + ("variant".into(), rgba(0x83a598ff).into()), + ("type".into(), rgba(0xfabd2eff).into()), + ("string.regex".into(), rgba(0xfe7f18ff).into()), + ("function.builtin".into(), rgba(0xfb4833ff).into()), + ("title".into(), rgba(0xb8bb25ff).into()), + ("string".into(), rgba(0xb8bb25ff).into()), + ("operator".into(), rgba(0x8ec07cff).into()), + ("embedded".into(), rgba(0x8ec07cff).into()), + ("punctuation.bracket".into(), rgba(0xa89984ff).into()), + ("string.special".into(), rgba(0xd3869bff).into()), + ("attribute".into(), rgba(0x83a598ff).into()), + ("comment".into(), rgba(0xa89984ff).into()), + ("link_text".into(), rgba(0x8ec07cff).into()), + ("punctuation.special".into(), rgba(0xe5d5adff).into()), + ("punctuation.list_marker".into(), rgba(0xebdbb2ff).into()), + ("comment.doc".into(), rgba(0xc6b697ff).into()), + ("preproc".into(), rgba(0xfbf1c7ff).into()), + ("text.literal".into(), rgba(0x83a598ff).into()), + ("function".into(), rgba(0xb8bb25ff).into()), + ("predictive".into(), rgba(0x717363ff).into()), + ("emphasis.strong".into(), rgba(0x83a598ff).into()), + ("punctuation".into(), rgba(0xd5c4a1ff).into()), + ("string.special.symbol".into(), rgba(0x8ec07cff).into()), + ("property".into(), rgba(0xebdbb2ff).into()), + ("keyword".into(), rgba(0xfb4833ff).into()), + ("constructor".into(), rgba(0x83a598ff).into()), + ("tag".into(), rgba(0x8ec07cff).into()), + ("variable".into(), rgba(0x83a598ff).into()), + ("enum".into(), rgba(0xfe7f18ff).into()), + ("hint".into(), rgba(0x8c957dff).into()), + ("number".into(), rgba(0xd3869bff).into()), + ("constant".into(), rgba(0xfabd2eff).into()), + ("boolean".into(), rgba(0xd3869bff).into()), + ("link_uri".into(), rgba(0xd3869bff).into()), + ("string.escape".into(), rgba(0xc6b697ff).into()), + ("emphasis".into(), rgba(0x83a598ff).into()), + ], + }, + status_bar: rgba(0x4c4642ff).into(), + title_bar: rgba(0x4c4642ff).into(), + toolbar: rgba(0x1d2021ff).into(), + tab_bar: rgba(0x393634ff).into(), + editor: rgba(0x1d2021ff).into(), + editor_subheader: rgba(0x393634ff).into(), + editor_active_line: rgba(0x393634ff).into(), + terminal: rgba(0x1d2021ff).into(), + image_fallback_background: rgba(0x4c4642ff).into(), + git_created: rgba(0xb7bb26ff).into(), + git_modified: rgba(0x83a598ff).into(), + git_deleted: rgba(0xfb4a35ff).into(), + git_conflict: rgba(0xf9bd2fff).into(), + git_ignored: rgba(0x998b78ff).into(), + git_renamed: rgba(0xf9bd2fff).into(), + players: [ + PlayerTheme { + cursor: rgba(0x83a598ff).into(), + selection: rgba(0x83a5983d).into(), + }, + PlayerTheme { + cursor: rgba(0xb7bb26ff).into(), + selection: rgba(0xb7bb263d).into(), + }, + PlayerTheme { + cursor: rgba(0xa89984ff).into(), + selection: rgba(0xa899843d).into(), + }, + PlayerTheme { + cursor: rgba(0xfd801bff).into(), + selection: rgba(0xfd801b3d).into(), + }, + PlayerTheme { + cursor: rgba(0xd3869bff).into(), + selection: rgba(0xd3869b3d).into(), + }, + PlayerTheme { + cursor: rgba(0x8ec07cff).into(), + selection: rgba(0x8ec07c3d).into(), + }, + PlayerTheme { + cursor: rgba(0xfb4a35ff).into(), + selection: rgba(0xfb4a353d).into(), + }, + PlayerTheme { + cursor: rgba(0xf9bd2fff).into(), + selection: rgba(0xf9bd2f3d).into(), + }, + ], + } +} diff --git a/crates/theme2/src/themes/gruvbox_dark_soft.rs b/crates/theme2/src/themes/gruvbox_dark_soft.rs new file mode 100644 index 0000000000..6a6423389e --- /dev/null +++ b/crates/theme2/src/themes/gruvbox_dark_soft.rs @@ -0,0 +1,131 @@ +use gpui2::rgba; + +use crate::{PlayerTheme, SyntaxTheme, Theme, ThemeMetadata}; + +pub fn gruvbox_dark_soft() -> Theme { + Theme { + metadata: ThemeMetadata { + name: "Gruvbox Dark Soft".into(), + is_light: false, + }, + transparent: rgba(0x00000000).into(), + mac_os_traffic_light_red: rgba(0xec695eff).into(), + mac_os_traffic_light_yellow: rgba(0xf4bf4eff).into(), + mac_os_traffic_light_green: rgba(0x61c553ff).into(), + border: rgba(0x5b534dff).into(), + border_variant: rgba(0x5b534dff).into(), + border_focused: rgba(0x303a36ff).into(), + border_transparent: rgba(0x00000000).into(), + elevated_surface: rgba(0x4c4642ff).into(), + surface: rgba(0x3b3735ff).into(), + background: rgba(0x4c4642ff).into(), + filled_element: rgba(0x4c4642ff).into(), + filled_element_hover: rgba(0xffffff1e).into(), + filled_element_active: rgba(0xffffff28).into(), + filled_element_selected: rgba(0x1e2321ff).into(), + filled_element_disabled: rgba(0x00000000).into(), + ghost_element: rgba(0x00000000).into(), + ghost_element_hover: rgba(0xffffff14).into(), + ghost_element_active: rgba(0xffffff1e).into(), + ghost_element_selected: rgba(0x1e2321ff).into(), + ghost_element_disabled: rgba(0x00000000).into(), + text: rgba(0xfbf1c7ff).into(), + text_muted: rgba(0xc5b597ff).into(), + text_placeholder: rgba(0xfb4a35ff).into(), + text_disabled: rgba(0x998b78ff).into(), + text_accent: rgba(0x83a598ff).into(), + icon_muted: rgba(0xc5b597ff).into(), + syntax: SyntaxTheme { + highlights: vec![ + ("punctuation.special".into(), rgba(0xe5d5adff).into()), + ("attribute".into(), rgba(0x83a598ff).into()), + ("preproc".into(), rgba(0xfbf1c7ff).into()), + ("keyword".into(), rgba(0xfb4833ff).into()), + ("emphasis".into(), rgba(0x83a598ff).into()), + ("punctuation.delimiter".into(), rgba(0xe5d5adff).into()), + ("punctuation.bracket".into(), rgba(0xa89984ff).into()), + ("comment".into(), rgba(0xa89984ff).into()), + ("text.literal".into(), rgba(0x83a598ff).into()), + ("predictive".into(), rgba(0x717363ff).into()), + ("link_text".into(), rgba(0x8ec07cff).into()), + ("variant".into(), rgba(0x83a598ff).into()), + ("label".into(), rgba(0x83a598ff).into()), + ("function".into(), rgba(0xb8bb25ff).into()), + ("string.regex".into(), rgba(0xfe7f18ff).into()), + ("boolean".into(), rgba(0xd3869bff).into()), + ("number".into(), rgba(0xd3869bff).into()), + ("string.escape".into(), rgba(0xc6b697ff).into()), + ("constructor".into(), rgba(0x83a598ff).into()), + ("link_uri".into(), rgba(0xd3869bff).into()), + ("string.special.symbol".into(), rgba(0x8ec07cff).into()), + ("type".into(), rgba(0xfabd2eff).into()), + ("function.builtin".into(), rgba(0xfb4833ff).into()), + ("title".into(), rgba(0xb8bb25ff).into()), + ("primary".into(), rgba(0xebdbb2ff).into()), + ("tag".into(), rgba(0x8ec07cff).into()), + ("constant".into(), rgba(0xfabd2eff).into()), + ("emphasis.strong".into(), rgba(0x83a598ff).into()), + ("string.special".into(), rgba(0xd3869bff).into()), + ("hint".into(), rgba(0x8c957dff).into()), + ("comment.doc".into(), rgba(0xc6b697ff).into()), + ("property".into(), rgba(0xebdbb2ff).into()), + ("embedded".into(), rgba(0x8ec07cff).into()), + ("operator".into(), rgba(0x8ec07cff).into()), + ("punctuation".into(), rgba(0xd5c4a1ff).into()), + ("variable".into(), rgba(0x83a598ff).into()), + ("enum".into(), rgba(0xfe7f18ff).into()), + ("punctuation.list_marker".into(), rgba(0xebdbb2ff).into()), + ("string".into(), rgba(0xb8bb25ff).into()), + ], + }, + status_bar: rgba(0x4c4642ff).into(), + title_bar: rgba(0x4c4642ff).into(), + toolbar: rgba(0x32302fff).into(), + tab_bar: rgba(0x3b3735ff).into(), + editor: rgba(0x32302fff).into(), + editor_subheader: rgba(0x3b3735ff).into(), + editor_active_line: rgba(0x3b3735ff).into(), + terminal: rgba(0x32302fff).into(), + image_fallback_background: rgba(0x4c4642ff).into(), + git_created: rgba(0xb7bb26ff).into(), + git_modified: rgba(0x83a598ff).into(), + git_deleted: rgba(0xfb4a35ff).into(), + git_conflict: rgba(0xf9bd2fff).into(), + git_ignored: rgba(0x998b78ff).into(), + git_renamed: rgba(0xf9bd2fff).into(), + players: [ + PlayerTheme { + cursor: rgba(0x83a598ff).into(), + selection: rgba(0x83a5983d).into(), + }, + PlayerTheme { + cursor: rgba(0xb7bb26ff).into(), + selection: rgba(0xb7bb263d).into(), + }, + PlayerTheme { + cursor: rgba(0xa89984ff).into(), + selection: rgba(0xa899843d).into(), + }, + PlayerTheme { + cursor: rgba(0xfd801bff).into(), + selection: rgba(0xfd801b3d).into(), + }, + PlayerTheme { + cursor: rgba(0xd3869bff).into(), + selection: rgba(0xd3869b3d).into(), + }, + PlayerTheme { + cursor: rgba(0x8ec07cff).into(), + selection: rgba(0x8ec07c3d).into(), + }, + PlayerTheme { + cursor: rgba(0xfb4a35ff).into(), + selection: rgba(0xfb4a353d).into(), + }, + PlayerTheme { + cursor: rgba(0xf9bd2fff).into(), + selection: rgba(0xf9bd2f3d).into(), + }, + ], + } +} diff --git a/crates/theme2/src/themes/gruvbox_light.rs b/crates/theme2/src/themes/gruvbox_light.rs new file mode 100644 index 0000000000..7582f8bd8a --- /dev/null +++ b/crates/theme2/src/themes/gruvbox_light.rs @@ -0,0 +1,131 @@ +use gpui2::rgba; + +use crate::{PlayerTheme, SyntaxTheme, Theme, ThemeMetadata}; + +pub fn gruvbox_light() -> Theme { + Theme { + metadata: ThemeMetadata { + name: "Gruvbox Light".into(), + is_light: true, + }, + transparent: rgba(0x00000000).into(), + mac_os_traffic_light_red: rgba(0xec695eff).into(), + mac_os_traffic_light_yellow: rgba(0xf4bf4eff).into(), + mac_os_traffic_light_green: rgba(0x61c553ff).into(), + border: rgba(0xc8b899ff).into(), + border_variant: rgba(0xc8b899ff).into(), + border_focused: rgba(0xadc5ccff).into(), + border_transparent: rgba(0x00000000).into(), + elevated_surface: rgba(0xd9c8a4ff).into(), + surface: rgba(0xecddb4ff).into(), + background: rgba(0xd9c8a4ff).into(), + filled_element: rgba(0xd9c8a4ff).into(), + filled_element_hover: rgba(0xffffff1e).into(), + filled_element_active: rgba(0xffffff28).into(), + filled_element_selected: rgba(0xd2dee2ff).into(), + filled_element_disabled: rgba(0x00000000).into(), + ghost_element: rgba(0x00000000).into(), + ghost_element_hover: rgba(0xffffff14).into(), + ghost_element_active: rgba(0xffffff1e).into(), + ghost_element_selected: rgba(0xd2dee2ff).into(), + ghost_element_disabled: rgba(0x00000000).into(), + text: rgba(0x282828ff).into(), + text_muted: rgba(0x5f5650ff).into(), + text_placeholder: rgba(0x9d0308ff).into(), + text_disabled: rgba(0x897b6eff).into(), + text_accent: rgba(0x0b6678ff).into(), + icon_muted: rgba(0x5f5650ff).into(), + syntax: SyntaxTheme { + highlights: vec![ + ("number".into(), rgba(0x8f3e71ff).into()), + ("link_text".into(), rgba(0x427b58ff).into()), + ("string.special".into(), rgba(0x8f3e71ff).into()), + ("string.special.symbol".into(), rgba(0x427b58ff).into()), + ("function".into(), rgba(0x79740eff).into()), + ("title".into(), rgba(0x79740eff).into()), + ("emphasis".into(), rgba(0x0b6678ff).into()), + ("punctuation".into(), rgba(0x3c3836ff).into()), + ("string.escape".into(), rgba(0x5d544eff).into()), + ("type".into(), rgba(0xb57613ff).into()), + ("string".into(), rgba(0x79740eff).into()), + ("keyword".into(), rgba(0x9d0006ff).into()), + ("tag".into(), rgba(0x427b58ff).into()), + ("primary".into(), rgba(0x282828ff).into()), + ("link_uri".into(), rgba(0x8f3e71ff).into()), + ("comment.doc".into(), rgba(0x5d544eff).into()), + ("boolean".into(), rgba(0x8f3e71ff).into()), + ("embedded".into(), rgba(0x427b58ff).into()), + ("hint".into(), rgba(0x677562ff).into()), + ("emphasis.strong".into(), rgba(0x0b6678ff).into()), + ("operator".into(), rgba(0x427b58ff).into()), + ("label".into(), rgba(0x0b6678ff).into()), + ("comment".into(), rgba(0x7c6f64ff).into()), + ("function.builtin".into(), rgba(0x9d0006ff).into()), + ("punctuation.bracket".into(), rgba(0x665c54ff).into()), + ("text.literal".into(), rgba(0x066578ff).into()), + ("string.regex".into(), rgba(0xaf3a02ff).into()), + ("property".into(), rgba(0x282828ff).into()), + ("attribute".into(), rgba(0x0b6678ff).into()), + ("punctuation.delimiter".into(), rgba(0x413d3aff).into()), + ("constructor".into(), rgba(0x0b6678ff).into()), + ("variable".into(), rgba(0x066578ff).into()), + ("constant".into(), rgba(0xb57613ff).into()), + ("preproc".into(), rgba(0x282828ff).into()), + ("punctuation.special".into(), rgba(0x413d3aff).into()), + ("punctuation.list_marker".into(), rgba(0x282828ff).into()), + ("variant".into(), rgba(0x0b6678ff).into()), + ("predictive".into(), rgba(0x7c9780ff).into()), + ("enum".into(), rgba(0xaf3a02ff).into()), + ], + }, + status_bar: rgba(0xd9c8a4ff).into(), + title_bar: rgba(0xd9c8a4ff).into(), + toolbar: rgba(0xfbf1c7ff).into(), + tab_bar: rgba(0xecddb4ff).into(), + editor: rgba(0xfbf1c7ff).into(), + editor_subheader: rgba(0xecddb4ff).into(), + editor_active_line: rgba(0xecddb4ff).into(), + terminal: rgba(0xfbf1c7ff).into(), + image_fallback_background: rgba(0xd9c8a4ff).into(), + git_created: rgba(0x797410ff).into(), + git_modified: rgba(0x0b6678ff).into(), + git_deleted: rgba(0x9d0308ff).into(), + git_conflict: rgba(0xb57615ff).into(), + git_ignored: rgba(0x897b6eff).into(), + git_renamed: rgba(0xb57615ff).into(), + players: [ + PlayerTheme { + cursor: rgba(0x0b6678ff).into(), + selection: rgba(0x0b66783d).into(), + }, + PlayerTheme { + cursor: rgba(0x797410ff).into(), + selection: rgba(0x7974103d).into(), + }, + PlayerTheme { + cursor: rgba(0x7c6f64ff).into(), + selection: rgba(0x7c6f643d).into(), + }, + PlayerTheme { + cursor: rgba(0xaf3a04ff).into(), + selection: rgba(0xaf3a043d).into(), + }, + PlayerTheme { + cursor: rgba(0x8f3f70ff).into(), + selection: rgba(0x8f3f703d).into(), + }, + PlayerTheme { + cursor: rgba(0x437b59ff).into(), + selection: rgba(0x437b593d).into(), + }, + PlayerTheme { + cursor: rgba(0x9d0308ff).into(), + selection: rgba(0x9d03083d).into(), + }, + PlayerTheme { + cursor: rgba(0xb57615ff).into(), + selection: rgba(0xb576153d).into(), + }, + ], + } +} diff --git a/crates/theme2/src/themes/gruvbox_light_hard.rs b/crates/theme2/src/themes/gruvbox_light_hard.rs new file mode 100644 index 0000000000..e5e3fe54cf --- /dev/null +++ b/crates/theme2/src/themes/gruvbox_light_hard.rs @@ -0,0 +1,131 @@ +use gpui2::rgba; + +use crate::{PlayerTheme, SyntaxTheme, Theme, ThemeMetadata}; + +pub fn gruvbox_light_hard() -> Theme { + Theme { + metadata: ThemeMetadata { + name: "Gruvbox Light Hard".into(), + is_light: true, + }, + transparent: rgba(0x00000000).into(), + mac_os_traffic_light_red: rgba(0xec695eff).into(), + mac_os_traffic_light_yellow: rgba(0xf4bf4eff).into(), + mac_os_traffic_light_green: rgba(0x61c553ff).into(), + border: rgba(0xc8b899ff).into(), + border_variant: rgba(0xc8b899ff).into(), + border_focused: rgba(0xadc5ccff).into(), + border_transparent: rgba(0x00000000).into(), + elevated_surface: rgba(0xd9c8a4ff).into(), + surface: rgba(0xecddb5ff).into(), + background: rgba(0xd9c8a4ff).into(), + filled_element: rgba(0xd9c8a4ff).into(), + filled_element_hover: rgba(0xffffff1e).into(), + filled_element_active: rgba(0xffffff28).into(), + filled_element_selected: rgba(0xd2dee2ff).into(), + filled_element_disabled: rgba(0x00000000).into(), + ghost_element: rgba(0x00000000).into(), + ghost_element_hover: rgba(0xffffff14).into(), + ghost_element_active: rgba(0xffffff1e).into(), + ghost_element_selected: rgba(0xd2dee2ff).into(), + ghost_element_disabled: rgba(0x00000000).into(), + text: rgba(0x282828ff).into(), + text_muted: rgba(0x5f5650ff).into(), + text_placeholder: rgba(0x9d0308ff).into(), + text_disabled: rgba(0x897b6eff).into(), + text_accent: rgba(0x0b6678ff).into(), + icon_muted: rgba(0x5f5650ff).into(), + syntax: SyntaxTheme { + highlights: vec![ + ("label".into(), rgba(0x0b6678ff).into()), + ("hint".into(), rgba(0x677562ff).into()), + ("boolean".into(), rgba(0x8f3e71ff).into()), + ("function.builtin".into(), rgba(0x9d0006ff).into()), + ("constant".into(), rgba(0xb57613ff).into()), + ("preproc".into(), rgba(0x282828ff).into()), + ("predictive".into(), rgba(0x7c9780ff).into()), + ("string".into(), rgba(0x79740eff).into()), + ("comment.doc".into(), rgba(0x5d544eff).into()), + ("function".into(), rgba(0x79740eff).into()), + ("title".into(), rgba(0x79740eff).into()), + ("text.literal".into(), rgba(0x066578ff).into()), + ("punctuation.bracket".into(), rgba(0x665c54ff).into()), + ("string.escape".into(), rgba(0x5d544eff).into()), + ("punctuation.delimiter".into(), rgba(0x413d3aff).into()), + ("string.special.symbol".into(), rgba(0x427b58ff).into()), + ("type".into(), rgba(0xb57613ff).into()), + ("constructor".into(), rgba(0x0b6678ff).into()), + ("property".into(), rgba(0x282828ff).into()), + ("comment".into(), rgba(0x7c6f64ff).into()), + ("enum".into(), rgba(0xaf3a02ff).into()), + ("emphasis".into(), rgba(0x0b6678ff).into()), + ("embedded".into(), rgba(0x427b58ff).into()), + ("operator".into(), rgba(0x427b58ff).into()), + ("attribute".into(), rgba(0x0b6678ff).into()), + ("emphasis.strong".into(), rgba(0x0b6678ff).into()), + ("link_text".into(), rgba(0x427b58ff).into()), + ("punctuation.special".into(), rgba(0x413d3aff).into()), + ("punctuation.list_marker".into(), rgba(0x282828ff).into()), + ("variant".into(), rgba(0x0b6678ff).into()), + ("primary".into(), rgba(0x282828ff).into()), + ("number".into(), rgba(0x8f3e71ff).into()), + ("tag".into(), rgba(0x427b58ff).into()), + ("keyword".into(), rgba(0x9d0006ff).into()), + ("link_uri".into(), rgba(0x8f3e71ff).into()), + ("string.regex".into(), rgba(0xaf3a02ff).into()), + ("variable".into(), rgba(0x066578ff).into()), + ("string.special".into(), rgba(0x8f3e71ff).into()), + ("punctuation".into(), rgba(0x3c3836ff).into()), + ], + }, + status_bar: rgba(0xd9c8a4ff).into(), + title_bar: rgba(0xd9c8a4ff).into(), + toolbar: rgba(0xf9f5d7ff).into(), + tab_bar: rgba(0xecddb5ff).into(), + editor: rgba(0xf9f5d7ff).into(), + editor_subheader: rgba(0xecddb5ff).into(), + editor_active_line: rgba(0xecddb5ff).into(), + terminal: rgba(0xf9f5d7ff).into(), + image_fallback_background: rgba(0xd9c8a4ff).into(), + git_created: rgba(0x797410ff).into(), + git_modified: rgba(0x0b6678ff).into(), + git_deleted: rgba(0x9d0308ff).into(), + git_conflict: rgba(0xb57615ff).into(), + git_ignored: rgba(0x897b6eff).into(), + git_renamed: rgba(0xb57615ff).into(), + players: [ + PlayerTheme { + cursor: rgba(0x0b6678ff).into(), + selection: rgba(0x0b66783d).into(), + }, + PlayerTheme { + cursor: rgba(0x797410ff).into(), + selection: rgba(0x7974103d).into(), + }, + PlayerTheme { + cursor: rgba(0x7c6f64ff).into(), + selection: rgba(0x7c6f643d).into(), + }, + PlayerTheme { + cursor: rgba(0xaf3a04ff).into(), + selection: rgba(0xaf3a043d).into(), + }, + PlayerTheme { + cursor: rgba(0x8f3f70ff).into(), + selection: rgba(0x8f3f703d).into(), + }, + PlayerTheme { + cursor: rgba(0x437b59ff).into(), + selection: rgba(0x437b593d).into(), + }, + PlayerTheme { + cursor: rgba(0x9d0308ff).into(), + selection: rgba(0x9d03083d).into(), + }, + PlayerTheme { + cursor: rgba(0xb57615ff).into(), + selection: rgba(0xb576153d).into(), + }, + ], + } +} diff --git a/crates/theme2/src/themes/gruvbox_light_soft.rs b/crates/theme2/src/themes/gruvbox_light_soft.rs new file mode 100644 index 0000000000..15574e2960 --- /dev/null +++ b/crates/theme2/src/themes/gruvbox_light_soft.rs @@ -0,0 +1,131 @@ +use gpui2::rgba; + +use crate::{PlayerTheme, SyntaxTheme, Theme, ThemeMetadata}; + +pub fn gruvbox_light_soft() -> Theme { + Theme { + metadata: ThemeMetadata { + name: "Gruvbox Light Soft".into(), + is_light: true, + }, + transparent: rgba(0x00000000).into(), + mac_os_traffic_light_red: rgba(0xec695eff).into(), + mac_os_traffic_light_yellow: rgba(0xf4bf4eff).into(), + mac_os_traffic_light_green: rgba(0x61c553ff).into(), + border: rgba(0xc8b899ff).into(), + border_variant: rgba(0xc8b899ff).into(), + border_focused: rgba(0xadc5ccff).into(), + border_transparent: rgba(0x00000000).into(), + elevated_surface: rgba(0xd9c8a4ff).into(), + surface: rgba(0xecdcb3ff).into(), + background: rgba(0xd9c8a4ff).into(), + filled_element: rgba(0xd9c8a4ff).into(), + filled_element_hover: rgba(0xffffff1e).into(), + filled_element_active: rgba(0xffffff28).into(), + filled_element_selected: rgba(0xd2dee2ff).into(), + filled_element_disabled: rgba(0x00000000).into(), + ghost_element: rgba(0x00000000).into(), + ghost_element_hover: rgba(0xffffff14).into(), + ghost_element_active: rgba(0xffffff1e).into(), + ghost_element_selected: rgba(0xd2dee2ff).into(), + ghost_element_disabled: rgba(0x00000000).into(), + text: rgba(0x282828ff).into(), + text_muted: rgba(0x5f5650ff).into(), + text_placeholder: rgba(0x9d0308ff).into(), + text_disabled: rgba(0x897b6eff).into(), + text_accent: rgba(0x0b6678ff).into(), + icon_muted: rgba(0x5f5650ff).into(), + syntax: SyntaxTheme { + highlights: vec![ + ("preproc".into(), rgba(0x282828ff).into()), + ("punctuation.list_marker".into(), rgba(0x282828ff).into()), + ("string".into(), rgba(0x79740eff).into()), + ("constant".into(), rgba(0xb57613ff).into()), + ("keyword".into(), rgba(0x9d0006ff).into()), + ("string.special.symbol".into(), rgba(0x427b58ff).into()), + ("comment.doc".into(), rgba(0x5d544eff).into()), + ("hint".into(), rgba(0x677562ff).into()), + ("number".into(), rgba(0x8f3e71ff).into()), + ("enum".into(), rgba(0xaf3a02ff).into()), + ("emphasis".into(), rgba(0x0b6678ff).into()), + ("operator".into(), rgba(0x427b58ff).into()), + ("comment".into(), rgba(0x7c6f64ff).into()), + ("embedded".into(), rgba(0x427b58ff).into()), + ("type".into(), rgba(0xb57613ff).into()), + ("title".into(), rgba(0x79740eff).into()), + ("constructor".into(), rgba(0x0b6678ff).into()), + ("punctuation.delimiter".into(), rgba(0x413d3aff).into()), + ("function".into(), rgba(0x79740eff).into()), + ("link_uri".into(), rgba(0x8f3e71ff).into()), + ("emphasis.strong".into(), rgba(0x0b6678ff).into()), + ("boolean".into(), rgba(0x8f3e71ff).into()), + ("function.builtin".into(), rgba(0x9d0006ff).into()), + ("predictive".into(), rgba(0x7c9780ff).into()), + ("string.regex".into(), rgba(0xaf3a02ff).into()), + ("tag".into(), rgba(0x427b58ff).into()), + ("text.literal".into(), rgba(0x066578ff).into()), + ("punctuation".into(), rgba(0x3c3836ff).into()), + ("punctuation.bracket".into(), rgba(0x665c54ff).into()), + ("variable".into(), rgba(0x066578ff).into()), + ("attribute".into(), rgba(0x0b6678ff).into()), + ("string.special".into(), rgba(0x8f3e71ff).into()), + ("label".into(), rgba(0x0b6678ff).into()), + ("string.escape".into(), rgba(0x5d544eff).into()), + ("link_text".into(), rgba(0x427b58ff).into()), + ("punctuation.special".into(), rgba(0x413d3aff).into()), + ("property".into(), rgba(0x282828ff).into()), + ("variant".into(), rgba(0x0b6678ff).into()), + ("primary".into(), rgba(0x282828ff).into()), + ], + }, + status_bar: rgba(0xd9c8a4ff).into(), + title_bar: rgba(0xd9c8a4ff).into(), + toolbar: rgba(0xf2e5bcff).into(), + tab_bar: rgba(0xecdcb3ff).into(), + editor: rgba(0xf2e5bcff).into(), + editor_subheader: rgba(0xecdcb3ff).into(), + editor_active_line: rgba(0xecdcb3ff).into(), + terminal: rgba(0xf2e5bcff).into(), + image_fallback_background: rgba(0xd9c8a4ff).into(), + git_created: rgba(0x797410ff).into(), + git_modified: rgba(0x0b6678ff).into(), + git_deleted: rgba(0x9d0308ff).into(), + git_conflict: rgba(0xb57615ff).into(), + git_ignored: rgba(0x897b6eff).into(), + git_renamed: rgba(0xb57615ff).into(), + players: [ + PlayerTheme { + cursor: rgba(0x0b6678ff).into(), + selection: rgba(0x0b66783d).into(), + }, + PlayerTheme { + cursor: rgba(0x797410ff).into(), + selection: rgba(0x7974103d).into(), + }, + PlayerTheme { + cursor: rgba(0x7c6f64ff).into(), + selection: rgba(0x7c6f643d).into(), + }, + PlayerTheme { + cursor: rgba(0xaf3a04ff).into(), + selection: rgba(0xaf3a043d).into(), + }, + PlayerTheme { + cursor: rgba(0x8f3f70ff).into(), + selection: rgba(0x8f3f703d).into(), + }, + PlayerTheme { + cursor: rgba(0x437b59ff).into(), + selection: rgba(0x437b593d).into(), + }, + PlayerTheme { + cursor: rgba(0x9d0308ff).into(), + selection: rgba(0x9d03083d).into(), + }, + PlayerTheme { + cursor: rgba(0xb57615ff).into(), + selection: rgba(0xb576153d).into(), + }, + ], + } +} diff --git a/crates/theme2/src/themes/mod.rs b/crates/theme2/src/themes/mod.rs index 63a895c98c..17cd5ac6e0 100644 --- a/crates/theme2/src/themes/mod.rs +++ b/crates/theme2/src/themes/mod.rs @@ -1,7 +1,79 @@ +mod andromeda; +mod atelier_cave_dark; +mod atelier_cave_light; +mod atelier_dune_dark; +mod atelier_dune_light; +mod atelier_estuary_dark; +mod atelier_estuary_light; +mod atelier_forest_dark; +mod atelier_forest_light; +mod atelier_heath_dark; +mod atelier_heath_light; +mod atelier_lakeside_dark; +mod atelier_lakeside_light; +mod atelier_plateau_dark; +mod atelier_plateau_light; +mod atelier_savanna_dark; +mod atelier_savanna_light; +mod atelier_seaside_dark; +mod atelier_seaside_light; +mod atelier_sulphurpool_dark; +mod atelier_sulphurpool_light; +mod ayu_dark; +mod ayu_light; +mod ayu_mirage; +mod gruvbox_dark; +mod gruvbox_dark_hard; +mod gruvbox_dark_soft; +mod gruvbox_light; +mod gruvbox_light_hard; +mod gruvbox_light_soft; mod one_dark; +mod one_light; mod rose_pine; +mod rose_pine_dawn; +mod rose_pine_moon; mod sandcastle; +mod solarized_dark; +mod solarized_light; +mod summercamp; +pub use andromeda::*; +pub use atelier_cave_dark::*; +pub use atelier_cave_light::*; +pub use atelier_dune_dark::*; +pub use atelier_dune_light::*; +pub use atelier_estuary_dark::*; +pub use atelier_estuary_light::*; +pub use atelier_forest_dark::*; +pub use atelier_forest_light::*; +pub use atelier_heath_dark::*; +pub use atelier_heath_light::*; +pub use atelier_lakeside_dark::*; +pub use atelier_lakeside_light::*; +pub use atelier_plateau_dark::*; +pub use atelier_plateau_light::*; +pub use atelier_savanna_dark::*; +pub use atelier_savanna_light::*; +pub use atelier_seaside_dark::*; +pub use atelier_seaside_light::*; +pub use atelier_sulphurpool_dark::*; +pub use atelier_sulphurpool_light::*; +pub use ayu_dark::*; +pub use ayu_light::*; +pub use ayu_mirage::*; +pub use gruvbox_dark::*; +pub use gruvbox_dark_hard::*; +pub use gruvbox_dark_soft::*; +pub use gruvbox_light::*; +pub use gruvbox_light_hard::*; +pub use gruvbox_light_soft::*; pub use one_dark::*; +pub use one_light::*; pub use rose_pine::*; +pub use rose_pine_dawn::*; +pub use rose_pine_moon::*; pub use sandcastle::*; +pub use solarized_dark::*; +pub use solarized_light::*; +pub use summercamp::*; diff --git a/crates/theme2/src/themes/one_dark.rs b/crates/theme2/src/themes/one_dark.rs index c59f4da16a..c7408d1820 100644 --- a/crates/theme2/src/themes/one_dark.rs +++ b/crates/theme2/src/themes/one_dark.rs @@ -37,45 +37,45 @@ pub fn one_dark() -> Theme { icon_muted: rgba(0x838994ff).into(), syntax: SyntaxTheme { highlights: vec![ - ("link_uri".into(), rgba(0x6eb4bfff).into()), - ("number".into(), rgba(0xbf956aff).into()), - ("property".into(), rgba(0xd07277ff).into()), - ("boolean".into(), rgba(0xbf956aff).into()), - ("label".into(), rgba(0x74ade8ff).into()), - ("punctuation.list_marker".into(), rgba(0xd07277ff).into()), ("keyword".into(), rgba(0xb477cfff).into()), - ("punctuation.delimiter".into(), rgba(0xb2b9c6ff).into()), - ("string.special".into(), rgba(0xbf956aff).into()), - ("constant".into(), rgba(0xdfc184ff).into()), - ("punctuation".into(), rgba(0xacb2beff).into()), - ("variable.special".into(), rgba(0xbf956aff).into()), - ("preproc".into(), rgba(0xc8ccd4ff).into()), - ("enum".into(), rgba(0xd07277ff).into()), - ("attribute".into(), rgba(0x74ade8ff).into()), - ("emphasis.strong".into(), rgba(0xbf956aff).into()), - ("title".into(), rgba(0xd07277ff).into()), - ("hint".into(), rgba(0x5a6f89ff).into()), - ("emphasis".into(), rgba(0x74ade8ff).into()), - ("string.regex".into(), rgba(0xbf956aff).into()), - ("link_text".into(), rgba(0x73ade9ff).into()), - ("string".into(), rgba(0xa1c181ff).into()), ("comment.doc".into(), rgba(0x878e98ff).into()), - ("punctuation.special".into(), rgba(0xb1574bff).into()), - ("primary".into(), rgba(0xacb2beff).into()), - ("operator".into(), rgba(0x6eb4bfff).into()), - ("function".into(), rgba(0x73ade9ff).into()), - ("string.special.symbol".into(), rgba(0xbf956aff).into()), - ("type".into(), rgba(0x6eb4bfff).into()), ("variant".into(), rgba(0x73ade9ff).into()), + ("property".into(), rgba(0xd07277ff).into()), + ("function".into(), rgba(0x73ade9ff).into()), + ("type".into(), rgba(0x6eb4bfff).into()), ("tag".into(), rgba(0x74ade8ff).into()), - ("punctuation.bracket".into(), rgba(0xb2b9c6ff).into()), - ("embedded".into(), rgba(0xc8ccd4ff).into()), ("string.escape".into(), rgba(0x878e98ff).into()), - ("variable".into(), rgba(0xc8ccd4ff).into()), - ("predictive".into(), rgba(0x5a6a87ff).into()), + ("punctuation.bracket".into(), rgba(0xb2b9c6ff).into()), + ("hint".into(), rgba(0x5a6f89ff).into()), + ("punctuation".into(), rgba(0xacb2beff).into()), ("comment".into(), rgba(0x5d636fff).into()), - ("text.literal".into(), rgba(0xa1c181ff).into()), + ("emphasis".into(), rgba(0x74ade8ff).into()), + ("punctuation.special".into(), rgba(0xb1574bff).into()), + ("link_uri".into(), rgba(0x6eb4bfff).into()), + ("string.regex".into(), rgba(0xbf956aff).into()), ("constructor".into(), rgba(0x73ade9ff).into()), + ("operator".into(), rgba(0x6eb4bfff).into()), + ("constant".into(), rgba(0xdfc184ff).into()), + ("string.special".into(), rgba(0xbf956aff).into()), + ("emphasis.strong".into(), rgba(0xbf956aff).into()), + ("string.special.symbol".into(), rgba(0xbf956aff).into()), + ("primary".into(), rgba(0xacb2beff).into()), + ("preproc".into(), rgba(0xc8ccd4ff).into()), + ("string".into(), rgba(0xa1c181ff).into()), + ("punctuation.delimiter".into(), rgba(0xb2b9c6ff).into()), + ("embedded".into(), rgba(0xc8ccd4ff).into()), + ("enum".into(), rgba(0xd07277ff).into()), + ("variable.special".into(), rgba(0xbf956aff).into()), + ("text.literal".into(), rgba(0xa1c181ff).into()), + ("attribute".into(), rgba(0x74ade8ff).into()), + ("link_text".into(), rgba(0x73ade9ff).into()), + ("title".into(), rgba(0xd07277ff).into()), + ("predictive".into(), rgba(0x5a6a87ff).into()), + ("number".into(), rgba(0xbf956aff).into()), + ("label".into(), rgba(0x74ade8ff).into()), + ("variable".into(), rgba(0xc8ccd4ff).into()), + ("boolean".into(), rgba(0xbf956aff).into()), + ("punctuation.list_marker".into(), rgba(0xd07277ff).into()), ], }, status_bar: rgba(0x3b414dff).into(), diff --git a/crates/theme2/src/themes/one_light.rs b/crates/theme2/src/themes/one_light.rs new file mode 100644 index 0000000000..ee802d57d3 --- /dev/null +++ b/crates/theme2/src/themes/one_light.rs @@ -0,0 +1,131 @@ +use gpui2::rgba; + +use crate::{PlayerTheme, SyntaxTheme, Theme, ThemeMetadata}; + +pub fn one_light() -> Theme { + Theme { + metadata: ThemeMetadata { + name: "One Light".into(), + is_light: true, + }, + transparent: rgba(0x00000000).into(), + mac_os_traffic_light_red: rgba(0xec695eff).into(), + mac_os_traffic_light_yellow: rgba(0xf4bf4eff).into(), + mac_os_traffic_light_green: rgba(0x61c553ff).into(), + border: rgba(0xc9c9caff).into(), + border_variant: rgba(0xc9c9caff).into(), + border_focused: rgba(0xcbcdf6ff).into(), + border_transparent: rgba(0x00000000).into(), + elevated_surface: rgba(0xdcdcddff).into(), + surface: rgba(0xebebecff).into(), + background: rgba(0xdcdcddff).into(), + filled_element: rgba(0xdcdcddff).into(), + filled_element_hover: rgba(0xffffff1e).into(), + filled_element_active: rgba(0xffffff28).into(), + filled_element_selected: rgba(0xe2e2faff).into(), + filled_element_disabled: rgba(0x00000000).into(), + ghost_element: rgba(0x00000000).into(), + ghost_element_hover: rgba(0xffffff14).into(), + ghost_element_active: rgba(0xffffff1e).into(), + ghost_element_selected: rgba(0xe2e2faff).into(), + ghost_element_disabled: rgba(0x00000000).into(), + text: rgba(0x383a41ff).into(), + text_muted: rgba(0x7e8087ff).into(), + text_placeholder: rgba(0xd36151ff).into(), + text_disabled: rgba(0xa1a1a3ff).into(), + text_accent: rgba(0x5c78e2ff).into(), + icon_muted: rgba(0x7e8087ff).into(), + syntax: SyntaxTheme { + highlights: vec![ + ("string.special.symbol".into(), rgba(0xad6e26ff).into()), + ("hint".into(), rgba(0x9294beff).into()), + ("link_uri".into(), rgba(0x3882b7ff).into()), + ("type".into(), rgba(0x3882b7ff).into()), + ("string.regex".into(), rgba(0xad6e26ff).into()), + ("constant".into(), rgba(0x669f59ff).into()), + ("function".into(), rgba(0x5b79e3ff).into()), + ("string.special".into(), rgba(0xad6e26ff).into()), + ("punctuation.bracket".into(), rgba(0x4d4f52ff).into()), + ("variable".into(), rgba(0x383a41ff).into()), + ("punctuation".into(), rgba(0x383a41ff).into()), + ("property".into(), rgba(0xd3604fff).into()), + ("string".into(), rgba(0x649f57ff).into()), + ("predictive".into(), rgba(0x9b9ec6ff).into()), + ("attribute".into(), rgba(0x5c78e2ff).into()), + ("number".into(), rgba(0xad6e25ff).into()), + ("constructor".into(), rgba(0x5c78e2ff).into()), + ("embedded".into(), rgba(0x383a41ff).into()), + ("title".into(), rgba(0xd3604fff).into()), + ("tag".into(), rgba(0x5c78e2ff).into()), + ("boolean".into(), rgba(0xad6e25ff).into()), + ("punctuation.list_marker".into(), rgba(0xd3604fff).into()), + ("variant".into(), rgba(0x5b79e3ff).into()), + ("emphasis".into(), rgba(0x5c78e2ff).into()), + ("link_text".into(), rgba(0x5b79e3ff).into()), + ("comment".into(), rgba(0xa2a3a7ff).into()), + ("punctuation.special".into(), rgba(0xb92b46ff).into()), + ("emphasis.strong".into(), rgba(0xad6e25ff).into()), + ("primary".into(), rgba(0x383a41ff).into()), + ("punctuation.delimiter".into(), rgba(0x4d4f52ff).into()), + ("label".into(), rgba(0x5c78e2ff).into()), + ("keyword".into(), rgba(0xa449abff).into()), + ("string.escape".into(), rgba(0x7c7e86ff).into()), + ("text.literal".into(), rgba(0x649f57ff).into()), + ("variable.special".into(), rgba(0xad6e25ff).into()), + ("comment.doc".into(), rgba(0x7c7e86ff).into()), + ("enum".into(), rgba(0xd3604fff).into()), + ("operator".into(), rgba(0x3882b7ff).into()), + ("preproc".into(), rgba(0x383a41ff).into()), + ], + }, + status_bar: rgba(0xdcdcddff).into(), + title_bar: rgba(0xdcdcddff).into(), + toolbar: rgba(0xfafafaff).into(), + tab_bar: rgba(0xebebecff).into(), + editor: rgba(0xfafafaff).into(), + editor_subheader: rgba(0xebebecff).into(), + editor_active_line: rgba(0xebebecff).into(), + terminal: rgba(0xfafafaff).into(), + image_fallback_background: rgba(0xdcdcddff).into(), + git_created: rgba(0x669f59ff).into(), + git_modified: rgba(0x5c78e2ff).into(), + git_deleted: rgba(0xd36151ff).into(), + git_conflict: rgba(0xdec184ff).into(), + git_ignored: rgba(0xa1a1a3ff).into(), + git_renamed: rgba(0xdec184ff).into(), + players: [ + PlayerTheme { + cursor: rgba(0x5c78e2ff).into(), + selection: rgba(0x5c78e23d).into(), + }, + PlayerTheme { + cursor: rgba(0x669f59ff).into(), + selection: rgba(0x669f593d).into(), + }, + PlayerTheme { + cursor: rgba(0x984ea5ff).into(), + selection: rgba(0x984ea53d).into(), + }, + PlayerTheme { + cursor: rgba(0xad6e26ff).into(), + selection: rgba(0xad6e263d).into(), + }, + PlayerTheme { + cursor: rgba(0xa349abff).into(), + selection: rgba(0xa349ab3d).into(), + }, + PlayerTheme { + cursor: rgba(0x3a82b7ff).into(), + selection: rgba(0x3a82b73d).into(), + }, + PlayerTheme { + cursor: rgba(0xd36151ff).into(), + selection: rgba(0xd361513d).into(), + }, + PlayerTheme { + cursor: rgba(0xdec184ff).into(), + selection: rgba(0xdec1843d).into(), + }, + ], + } +} diff --git a/crates/theme2/src/themes/rose_pine.rs b/crates/theme2/src/themes/rose_pine.rs index 674422c408..f3bd454cdc 100644 --- a/crates/theme2/src/themes/rose_pine.rs +++ b/crates/theme2/src/themes/rose_pine.rs @@ -37,46 +37,46 @@ pub fn rose_pine() -> Theme { icon_muted: rgba(0x74708dff).into(), syntax: SyntaxTheme { highlights: vec![ - ("text.literal".into(), rgba(0xc4a7e6ff).into()), - ("string".into(), rgba(0xf5c177ff).into()), - ("enum".into(), rgba(0xc4a7e6ff).into()), - ("number".into(), rgba(0x5cc1a3ff).into()), - ("attribute".into(), rgba(0x9bced6ff).into()), - ("property".into(), rgba(0x9bced6ff).into()), - ("function".into(), rgba(0xebbcbaff).into()), - ("embedded".into(), rgba(0xe0def4ff).into()), ("punctuation.delimiter".into(), rgba(0x9d99b6ff).into()), - ("variant".into(), rgba(0x9bced6ff).into()), - ("operator".into(), rgba(0x30738fff).into()), - ("comment".into(), rgba(0x6e6a86ff).into()), - ("type.builtin".into(), rgba(0x9ccfd8ff).into()), - ("label".into(), rgba(0x9bced6ff).into()), - ("string.escape".into(), rgba(0x76728fff).into()), - ("type".into(), rgba(0x9ccfd8ff).into()), - ("constructor".into(), rgba(0x9bced6ff).into()), - ("punctuation.bracket".into(), rgba(0x9d99b6ff).into()), - ("function.method".into(), rgba(0xebbcbaff).into()), - ("tag".into(), rgba(0x9ccfd8ff).into()), - ("link_text".into(), rgba(0x9ccfd8ff).into()), - ("string.special".into(), rgba(0xc4a7e6ff).into()), - ("string.regex".into(), rgba(0xc4a7e6ff).into()), - ("preproc".into(), rgba(0xe0def4ff).into()), - ("emphasis.strong".into(), rgba(0x9bced6ff).into()), - ("emphasis".into(), rgba(0x9bced6ff).into()), - ("comment.doc".into(), rgba(0x76728fff).into()), - ("boolean".into(), rgba(0xebbcbaff).into()), - ("punctuation.list_marker".into(), rgba(0x9d99b6ff).into()), - ("hint".into(), rgba(0x5e768cff).into()), - ("title".into(), rgba(0xf5c177ff).into()), - ("variable".into(), rgba(0xe0def4ff).into()), - ("string.special.symbol".into(), rgba(0xc4a7e6ff).into()), - ("primary".into(), rgba(0xe0def4ff).into()), - ("predictive".into(), rgba(0x556b81ff).into()), - ("punctuation".into(), rgba(0x908caaff).into()), - ("constant".into(), rgba(0x5cc1a3ff).into()), + ("number".into(), rgba(0x5cc1a3ff).into()), ("punctuation.special".into(), rgba(0x9d99b6ff).into()), + ("string.escape".into(), rgba(0x76728fff).into()), + ("title".into(), rgba(0xf5c177ff).into()), + ("constant".into(), rgba(0x5cc1a3ff).into()), + ("string.regex".into(), rgba(0xc4a7e6ff).into()), + ("type.builtin".into(), rgba(0x9ccfd8ff).into()), + ("comment.doc".into(), rgba(0x76728fff).into()), + ("primary".into(), rgba(0xe0def4ff).into()), + ("string.special".into(), rgba(0xc4a7e6ff).into()), + ("punctuation".into(), rgba(0x908caaff).into()), + ("string.special.symbol".into(), rgba(0xc4a7e6ff).into()), + ("variant".into(), rgba(0x9bced6ff).into()), + ("function.method".into(), rgba(0xebbcbaff).into()), + ("comment".into(), rgba(0x6e6a86ff).into()), + ("boolean".into(), rgba(0xebbcbaff).into()), + ("preproc".into(), rgba(0xe0def4ff).into()), ("link_uri".into(), rgba(0xebbcbaff).into()), + ("hint".into(), rgba(0x5e768cff).into()), + ("attribute".into(), rgba(0x9bced6ff).into()), + ("text.literal".into(), rgba(0xc4a7e6ff).into()), + ("punctuation.list_marker".into(), rgba(0x9d99b6ff).into()), + ("operator".into(), rgba(0x30738fff).into()), + ("emphasis.strong".into(), rgba(0x9bced6ff).into()), ("keyword".into(), rgba(0x30738fff).into()), + ("enum".into(), rgba(0xc4a7e6ff).into()), + ("tag".into(), rgba(0x9ccfd8ff).into()), + ("constructor".into(), rgba(0x9bced6ff).into()), + ("function".into(), rgba(0xebbcbaff).into()), + ("string".into(), rgba(0xf5c177ff).into()), + ("type".into(), rgba(0x9ccfd8ff).into()), + ("emphasis".into(), rgba(0x9bced6ff).into()), + ("link_text".into(), rgba(0x9ccfd8ff).into()), + ("property".into(), rgba(0x9bced6ff).into()), + ("predictive".into(), rgba(0x556b81ff).into()), + ("punctuation.bracket".into(), rgba(0x9d99b6ff).into()), + ("embedded".into(), rgba(0xe0def4ff).into()), + ("variable".into(), rgba(0xe0def4ff).into()), + ("label".into(), rgba(0x9bced6ff).into()), ], }, status_bar: rgba(0x292738ff).into(), @@ -130,261 +130,3 @@ pub fn rose_pine() -> Theme { ], } } - -pub fn rose_pine_dawn() -> Theme { - Theme { - metadata: ThemeMetadata { - name: "Rosé Pine Dawn".into(), - is_light: true, - }, - transparent: rgba(0x00000000).into(), - mac_os_traffic_light_red: rgba(0xec695eff).into(), - mac_os_traffic_light_yellow: rgba(0xf4bf4eff).into(), - mac_os_traffic_light_green: rgba(0x61c553ff).into(), - border: rgba(0xdcd6d5ff).into(), - border_variant: rgba(0xdcd6d5ff).into(), - border_focused: rgba(0xc3d7dbff).into(), - border_transparent: rgba(0x00000000).into(), - elevated_surface: rgba(0xdcd8d8ff).into(), - surface: rgba(0xfef9f2ff).into(), - background: rgba(0xdcd8d8ff).into(), - filled_element: rgba(0xdcd8d8ff).into(), - filled_element_hover: rgba(0xffffff1e).into(), - filled_element_active: rgba(0xffffff28).into(), - filled_element_selected: rgba(0xdde9ebff).into(), - filled_element_disabled: rgba(0x00000000).into(), - ghost_element: rgba(0x00000000).into(), - ghost_element_hover: rgba(0xffffff14).into(), - ghost_element_active: rgba(0xffffff1e).into(), - ghost_element_selected: rgba(0xdde9ebff).into(), - ghost_element_disabled: rgba(0x00000000).into(), - text: rgba(0x575279ff).into(), - text_muted: rgba(0x706c8cff).into(), - text_placeholder: rgba(0xb4647aff).into(), - text_disabled: rgba(0x938fa3ff).into(), - text_accent: rgba(0x57949fff).into(), - icon_muted: rgba(0x706c8cff).into(), - syntax: SyntaxTheme { - highlights: vec![ - ("type".into(), rgba(0x55949fff).into()), - ("keyword".into(), rgba(0x276983ff).into()), - ("link_text".into(), rgba(0x55949fff).into()), - ("embedded".into(), rgba(0x575279ff).into()), - ("type.builtin".into(), rgba(0x55949fff).into()), - ("punctuation.delimiter".into(), rgba(0x635e82ff).into()), - ("text.literal".into(), rgba(0x9079a9ff).into()), - ("variant".into(), rgba(0x57949fff).into()), - ("string".into(), rgba(0xea9d34ff).into()), - ("hint".into(), rgba(0x7a92aaff).into()), - ("punctuation.special".into(), rgba(0x635e82ff).into()), - ("string.special".into(), rgba(0x9079a9ff).into()), - ("string.regex".into(), rgba(0x9079a9ff).into()), - ("operator".into(), rgba(0x276983ff).into()), - ("boolean".into(), rgba(0xd7827dff).into()), - ("constructor".into(), rgba(0x57949fff).into()), - ("punctuation".into(), rgba(0x797593ff).into()), - ("label".into(), rgba(0x57949fff).into()), - ("variable".into(), rgba(0x575279ff).into()), - ("tag".into(), rgba(0x55949fff).into()), - ("primary".into(), rgba(0x575279ff).into()), - ("link_uri".into(), rgba(0xd7827dff).into()), - ("punctuation.list_marker".into(), rgba(0x635e82ff).into()), - ("string.escape".into(), rgba(0x6e6a8bff).into()), - ("punctuation.bracket".into(), rgba(0x635e82ff).into()), - ("function".into(), rgba(0xd7827dff).into()), - ("preproc".into(), rgba(0x575279ff).into()), - ("function.method".into(), rgba(0xd7827dff).into()), - ("predictive".into(), rgba(0xa2acbeff).into()), - ("comment.doc".into(), rgba(0x6e6a8bff).into()), - ("comment".into(), rgba(0x9893a5ff).into()), - ("number".into(), rgba(0x3daa8eff).into()), - ("emphasis".into(), rgba(0x57949fff).into()), - ("title".into(), rgba(0xea9d34ff).into()), - ("enum".into(), rgba(0x9079a9ff).into()), - ("string.special.symbol".into(), rgba(0x9079a9ff).into()), - ("constant".into(), rgba(0x3daa8eff).into()), - ("emphasis.strong".into(), rgba(0x57949fff).into()), - ("property".into(), rgba(0x57949fff).into()), - ("attribute".into(), rgba(0x57949fff).into()), - ], - }, - status_bar: rgba(0xdcd8d8ff).into(), - title_bar: rgba(0xdcd8d8ff).into(), - toolbar: rgba(0xfaf4edff).into(), - tab_bar: rgba(0xfef9f2ff).into(), - editor: rgba(0xfaf4edff).into(), - editor_subheader: rgba(0xfef9f2ff).into(), - editor_active_line: rgba(0xfef9f2ff).into(), - terminal: rgba(0xfaf4edff).into(), - image_fallback_background: rgba(0xdcd8d8ff).into(), - git_created: rgba(0x3daa8eff).into(), - git_modified: rgba(0x57949fff).into(), - git_deleted: rgba(0xb4647aff).into(), - git_conflict: rgba(0xe99d35ff).into(), - git_ignored: rgba(0x938fa3ff).into(), - git_renamed: rgba(0xe99d35ff).into(), - players: [ - PlayerTheme { - cursor: rgba(0x57949fff).into(), - selection: rgba(0x57949f3d).into(), - }, - PlayerTheme { - cursor: rgba(0x3daa8eff).into(), - selection: rgba(0x3daa8e3d).into(), - }, - PlayerTheme { - cursor: rgba(0x7c697fff).into(), - selection: rgba(0x7c697f3d).into(), - }, - PlayerTheme { - cursor: rgba(0x9079a9ff).into(), - selection: rgba(0x9079a93d).into(), - }, - PlayerTheme { - cursor: rgba(0x9079a9ff).into(), - selection: rgba(0x9079a93d).into(), - }, - PlayerTheme { - cursor: rgba(0x296983ff).into(), - selection: rgba(0x2969833d).into(), - }, - PlayerTheme { - cursor: rgba(0xb4647aff).into(), - selection: rgba(0xb4647a3d).into(), - }, - PlayerTheme { - cursor: rgba(0xe99d35ff).into(), - selection: rgba(0xe99d353d).into(), - }, - ], - } -} - -pub fn rose_pine_moon() -> Theme { - Theme { - metadata: ThemeMetadata { - name: "Rosé Pine Moon".into(), - is_light: false, - }, - transparent: rgba(0x00000000).into(), - mac_os_traffic_light_red: rgba(0xec695eff).into(), - mac_os_traffic_light_yellow: rgba(0xf4bf4eff).into(), - mac_os_traffic_light_green: rgba(0x61c553ff).into(), - border: rgba(0x504c68ff).into(), - border_variant: rgba(0x504c68ff).into(), - border_focused: rgba(0x435255ff).into(), - border_transparent: rgba(0x00000000).into(), - elevated_surface: rgba(0x38354eff).into(), - surface: rgba(0x28253cff).into(), - background: rgba(0x38354eff).into(), - filled_element: rgba(0x38354eff).into(), - filled_element_hover: rgba(0xffffff1e).into(), - filled_element_active: rgba(0xffffff28).into(), - filled_element_selected: rgba(0x2f3639ff).into(), - filled_element_disabled: rgba(0x00000000).into(), - ghost_element: rgba(0x00000000).into(), - ghost_element_hover: rgba(0xffffff14).into(), - ghost_element_active: rgba(0xffffff1e).into(), - ghost_element_selected: rgba(0x2f3639ff).into(), - ghost_element_disabled: rgba(0x00000000).into(), - text: rgba(0xe0def4ff).into(), - text_muted: rgba(0x85819eff).into(), - text_placeholder: rgba(0xea6e92ff).into(), - text_disabled: rgba(0x605d7aff).into(), - text_accent: rgba(0x9bced6ff).into(), - icon_muted: rgba(0x85819eff).into(), - syntax: SyntaxTheme { - highlights: vec![ - ("embedded".into(), rgba(0xe0def4ff).into()), - ("link_uri".into(), rgba(0xea9a97ff).into()), - ("primary".into(), rgba(0xe0def4ff).into()), - ("punctuation.delimiter".into(), rgba(0xaeabc6ff).into()), - ("string.escape".into(), rgba(0x8682a0ff).into()), - ("attribute".into(), rgba(0x9bced6ff).into()), - ("constant".into(), rgba(0x5cc1a3ff).into()), - ("keyword".into(), rgba(0x3d8fb0ff).into()), - ("predictive".into(), rgba(0x516b83ff).into()), - ("label".into(), rgba(0x9bced6ff).into()), - ("comment.doc".into(), rgba(0x8682a0ff).into()), - ("emphasis".into(), rgba(0x9bced6ff).into()), - ("string".into(), rgba(0xf5c177ff).into()), - ("type".into(), rgba(0x9ccfd8ff).into()), - ("string.special".into(), rgba(0xc4a7e6ff).into()), - ("function".into(), rgba(0xea9a97ff).into()), - ("constructor".into(), rgba(0x9bced6ff).into()), - ("comment".into(), rgba(0x6e6a86ff).into()), - ("preproc".into(), rgba(0xe0def4ff).into()), - ("enum".into(), rgba(0xc4a7e6ff).into()), - ("punctuation.bracket".into(), rgba(0xaeabc6ff).into()), - ("number".into(), rgba(0x5cc1a3ff).into()), - ("hint".into(), rgba(0x728aa2ff).into()), - ("variant".into(), rgba(0x9bced6ff).into()), - ("link_text".into(), rgba(0x9ccfd8ff).into()), - ("property".into(), rgba(0x9bced6ff).into()), - ("punctuation.list_marker".into(), rgba(0xaeabc6ff).into()), - ("operator".into(), rgba(0x3d8fb0ff).into()), - ("title".into(), rgba(0xf5c177ff).into()), - ("punctuation".into(), rgba(0x908caaff).into()), - ("string.regex".into(), rgba(0xc4a7e6ff).into()), - ("tag".into(), rgba(0x9ccfd8ff).into()), - ("emphasis.strong".into(), rgba(0x9bced6ff).into()), - ("text.literal".into(), rgba(0xc4a7e6ff).into()), - ("punctuation.special".into(), rgba(0xaeabc6ff).into()), - ("boolean".into(), rgba(0xea9a97ff).into()), - ("type.builtin".into(), rgba(0x9ccfd8ff).into()), - ("function.method".into(), rgba(0xea9a97ff).into()), - ("variable".into(), rgba(0xe0def4ff).into()), - ("string.special.symbol".into(), rgba(0xc4a7e6ff).into()), - ], - }, - status_bar: rgba(0x38354eff).into(), - title_bar: rgba(0x38354eff).into(), - toolbar: rgba(0x232136ff).into(), - tab_bar: rgba(0x28253cff).into(), - editor: rgba(0x232136ff).into(), - editor_subheader: rgba(0x28253cff).into(), - editor_active_line: rgba(0x28253cff).into(), - terminal: rgba(0x232136ff).into(), - image_fallback_background: rgba(0x38354eff).into(), - git_created: rgba(0x5cc1a3ff).into(), - git_modified: rgba(0x9bced6ff).into(), - git_deleted: rgba(0xea6e92ff).into(), - git_conflict: rgba(0xf5c177ff).into(), - git_ignored: rgba(0x605d7aff).into(), - git_renamed: rgba(0xf5c177ff).into(), - players: [ - PlayerTheme { - cursor: rgba(0x9bced6ff).into(), - selection: rgba(0x9bced63d).into(), - }, - PlayerTheme { - cursor: rgba(0x5cc1a3ff).into(), - selection: rgba(0x5cc1a33d).into(), - }, - PlayerTheme { - cursor: rgba(0xa683a0ff).into(), - selection: rgba(0xa683a03d).into(), - }, - PlayerTheme { - cursor: rgba(0xc4a7e6ff).into(), - selection: rgba(0xc4a7e63d).into(), - }, - PlayerTheme { - cursor: rgba(0xc4a7e6ff).into(), - selection: rgba(0xc4a7e63d).into(), - }, - PlayerTheme { - cursor: rgba(0x3e8fb0ff).into(), - selection: rgba(0x3e8fb03d).into(), - }, - PlayerTheme { - cursor: rgba(0xea6e92ff).into(), - selection: rgba(0xea6e923d).into(), - }, - PlayerTheme { - cursor: rgba(0xf5c177ff).into(), - selection: rgba(0xf5c1773d).into(), - }, - ], - } -} diff --git a/crates/theme2/src/themes/rose_pine_dawn.rs b/crates/theme2/src/themes/rose_pine_dawn.rs new file mode 100644 index 0000000000..ba64bf9d99 --- /dev/null +++ b/crates/theme2/src/themes/rose_pine_dawn.rs @@ -0,0 +1,132 @@ +use gpui2::rgba; + +use crate::{PlayerTheme, SyntaxTheme, Theme, ThemeMetadata}; + +pub fn rose_pine_dawn() -> Theme { + Theme { + metadata: ThemeMetadata { + name: "Rosé Pine Dawn".into(), + is_light: true, + }, + transparent: rgba(0x00000000).into(), + mac_os_traffic_light_red: rgba(0xec695eff).into(), + mac_os_traffic_light_yellow: rgba(0xf4bf4eff).into(), + mac_os_traffic_light_green: rgba(0x61c553ff).into(), + border: rgba(0xdcd6d5ff).into(), + border_variant: rgba(0xdcd6d5ff).into(), + border_focused: rgba(0xc3d7dbff).into(), + border_transparent: rgba(0x00000000).into(), + elevated_surface: rgba(0xdcd8d8ff).into(), + surface: rgba(0xfef9f2ff).into(), + background: rgba(0xdcd8d8ff).into(), + filled_element: rgba(0xdcd8d8ff).into(), + filled_element_hover: rgba(0xffffff1e).into(), + filled_element_active: rgba(0xffffff28).into(), + filled_element_selected: rgba(0xdde9ebff).into(), + filled_element_disabled: rgba(0x00000000).into(), + ghost_element: rgba(0x00000000).into(), + ghost_element_hover: rgba(0xffffff14).into(), + ghost_element_active: rgba(0xffffff1e).into(), + ghost_element_selected: rgba(0xdde9ebff).into(), + ghost_element_disabled: rgba(0x00000000).into(), + text: rgba(0x575279ff).into(), + text_muted: rgba(0x706c8cff).into(), + text_placeholder: rgba(0xb4647aff).into(), + text_disabled: rgba(0x938fa3ff).into(), + text_accent: rgba(0x57949fff).into(), + icon_muted: rgba(0x706c8cff).into(), + syntax: SyntaxTheme { + highlights: vec![ + ("primary".into(), rgba(0x575279ff).into()), + ("attribute".into(), rgba(0x57949fff).into()), + ("operator".into(), rgba(0x276983ff).into()), + ("boolean".into(), rgba(0xd7827dff).into()), + ("tag".into(), rgba(0x55949fff).into()), + ("enum".into(), rgba(0x9079a9ff).into()), + ("embedded".into(), rgba(0x575279ff).into()), + ("label".into(), rgba(0x57949fff).into()), + ("function.method".into(), rgba(0xd7827dff).into()), + ("punctuation.list_marker".into(), rgba(0x635e82ff).into()), + ("punctuation.delimiter".into(), rgba(0x635e82ff).into()), + ("string".into(), rgba(0xea9d34ff).into()), + ("type".into(), rgba(0x55949fff).into()), + ("string.regex".into(), rgba(0x9079a9ff).into()), + ("variable".into(), rgba(0x575279ff).into()), + ("constructor".into(), rgba(0x57949fff).into()), + ("punctuation.bracket".into(), rgba(0x635e82ff).into()), + ("emphasis".into(), rgba(0x57949fff).into()), + ("comment.doc".into(), rgba(0x6e6a8bff).into()), + ("comment".into(), rgba(0x9893a5ff).into()), + ("keyword".into(), rgba(0x276983ff).into()), + ("preproc".into(), rgba(0x575279ff).into()), + ("string.special".into(), rgba(0x9079a9ff).into()), + ("string.escape".into(), rgba(0x6e6a8bff).into()), + ("constant".into(), rgba(0x3daa8eff).into()), + ("property".into(), rgba(0x57949fff).into()), + ("punctuation.special".into(), rgba(0x635e82ff).into()), + ("text.literal".into(), rgba(0x9079a9ff).into()), + ("type.builtin".into(), rgba(0x55949fff).into()), + ("string.special.symbol".into(), rgba(0x9079a9ff).into()), + ("link_uri".into(), rgba(0xd7827dff).into()), + ("number".into(), rgba(0x3daa8eff).into()), + ("emphasis.strong".into(), rgba(0x57949fff).into()), + ("function".into(), rgba(0xd7827dff).into()), + ("title".into(), rgba(0xea9d34ff).into()), + ("punctuation".into(), rgba(0x797593ff).into()), + ("link_text".into(), rgba(0x55949fff).into()), + ("variant".into(), rgba(0x57949fff).into()), + ("predictive".into(), rgba(0xa2acbeff).into()), + ("hint".into(), rgba(0x7a92aaff).into()), + ], + }, + status_bar: rgba(0xdcd8d8ff).into(), + title_bar: rgba(0xdcd8d8ff).into(), + toolbar: rgba(0xfaf4edff).into(), + tab_bar: rgba(0xfef9f2ff).into(), + editor: rgba(0xfaf4edff).into(), + editor_subheader: rgba(0xfef9f2ff).into(), + editor_active_line: rgba(0xfef9f2ff).into(), + terminal: rgba(0xfaf4edff).into(), + image_fallback_background: rgba(0xdcd8d8ff).into(), + git_created: rgba(0x3daa8eff).into(), + git_modified: rgba(0x57949fff).into(), + git_deleted: rgba(0xb4647aff).into(), + git_conflict: rgba(0xe99d35ff).into(), + git_ignored: rgba(0x938fa3ff).into(), + git_renamed: rgba(0xe99d35ff).into(), + players: [ + PlayerTheme { + cursor: rgba(0x57949fff).into(), + selection: rgba(0x57949f3d).into(), + }, + PlayerTheme { + cursor: rgba(0x3daa8eff).into(), + selection: rgba(0x3daa8e3d).into(), + }, + PlayerTheme { + cursor: rgba(0x7c697fff).into(), + selection: rgba(0x7c697f3d).into(), + }, + PlayerTheme { + cursor: rgba(0x9079a9ff).into(), + selection: rgba(0x9079a93d).into(), + }, + PlayerTheme { + cursor: rgba(0x9079a9ff).into(), + selection: rgba(0x9079a93d).into(), + }, + PlayerTheme { + cursor: rgba(0x296983ff).into(), + selection: rgba(0x2969833d).into(), + }, + PlayerTheme { + cursor: rgba(0xb4647aff).into(), + selection: rgba(0xb4647a3d).into(), + }, + PlayerTheme { + cursor: rgba(0xe99d35ff).into(), + selection: rgba(0xe99d353d).into(), + }, + ], + } +} diff --git a/crates/theme2/src/themes/rose_pine_moon.rs b/crates/theme2/src/themes/rose_pine_moon.rs new file mode 100644 index 0000000000..167b78afb5 --- /dev/null +++ b/crates/theme2/src/themes/rose_pine_moon.rs @@ -0,0 +1,132 @@ +use gpui2::rgba; + +use crate::{PlayerTheme, SyntaxTheme, Theme, ThemeMetadata}; + +pub fn rose_pine_moon() -> Theme { + Theme { + metadata: ThemeMetadata { + name: "Rosé Pine Moon".into(), + is_light: false, + }, + transparent: rgba(0x00000000).into(), + mac_os_traffic_light_red: rgba(0xec695eff).into(), + mac_os_traffic_light_yellow: rgba(0xf4bf4eff).into(), + mac_os_traffic_light_green: rgba(0x61c553ff).into(), + border: rgba(0x504c68ff).into(), + border_variant: rgba(0x504c68ff).into(), + border_focused: rgba(0x435255ff).into(), + border_transparent: rgba(0x00000000).into(), + elevated_surface: rgba(0x38354eff).into(), + surface: rgba(0x28253cff).into(), + background: rgba(0x38354eff).into(), + filled_element: rgba(0x38354eff).into(), + filled_element_hover: rgba(0xffffff1e).into(), + filled_element_active: rgba(0xffffff28).into(), + filled_element_selected: rgba(0x2f3639ff).into(), + filled_element_disabled: rgba(0x00000000).into(), + ghost_element: rgba(0x00000000).into(), + ghost_element_hover: rgba(0xffffff14).into(), + ghost_element_active: rgba(0xffffff1e).into(), + ghost_element_selected: rgba(0x2f3639ff).into(), + ghost_element_disabled: rgba(0x00000000).into(), + text: rgba(0xe0def4ff).into(), + text_muted: rgba(0x85819eff).into(), + text_placeholder: rgba(0xea6e92ff).into(), + text_disabled: rgba(0x605d7aff).into(), + text_accent: rgba(0x9bced6ff).into(), + icon_muted: rgba(0x85819eff).into(), + syntax: SyntaxTheme { + highlights: vec![ + ("type.builtin".into(), rgba(0x9ccfd8ff).into()), + ("variable".into(), rgba(0xe0def4ff).into()), + ("punctuation".into(), rgba(0x908caaff).into()), + ("number".into(), rgba(0x5cc1a3ff).into()), + ("comment".into(), rgba(0x6e6a86ff).into()), + ("string.special".into(), rgba(0xc4a7e6ff).into()), + ("string.escape".into(), rgba(0x8682a0ff).into()), + ("function.method".into(), rgba(0xea9a97ff).into()), + ("predictive".into(), rgba(0x516b83ff).into()), + ("punctuation.delimiter".into(), rgba(0xaeabc6ff).into()), + ("primary".into(), rgba(0xe0def4ff).into()), + ("link_text".into(), rgba(0x9ccfd8ff).into()), + ("string.regex".into(), rgba(0xc4a7e6ff).into()), + ("constructor".into(), rgba(0x9bced6ff).into()), + ("constant".into(), rgba(0x5cc1a3ff).into()), + ("emphasis.strong".into(), rgba(0x9bced6ff).into()), + ("function".into(), rgba(0xea9a97ff).into()), + ("hint".into(), rgba(0x728aa2ff).into()), + ("preproc".into(), rgba(0xe0def4ff).into()), + ("property".into(), rgba(0x9bced6ff).into()), + ("punctuation.list_marker".into(), rgba(0xaeabc6ff).into()), + ("emphasis".into(), rgba(0x9bced6ff).into()), + ("attribute".into(), rgba(0x9bced6ff).into()), + ("title".into(), rgba(0xf5c177ff).into()), + ("keyword".into(), rgba(0x3d8fb0ff).into()), + ("string".into(), rgba(0xf5c177ff).into()), + ("text.literal".into(), rgba(0xc4a7e6ff).into()), + ("embedded".into(), rgba(0xe0def4ff).into()), + ("comment.doc".into(), rgba(0x8682a0ff).into()), + ("variant".into(), rgba(0x9bced6ff).into()), + ("label".into(), rgba(0x9bced6ff).into()), + ("punctuation.special".into(), rgba(0xaeabc6ff).into()), + ("string.special.symbol".into(), rgba(0xc4a7e6ff).into()), + ("tag".into(), rgba(0x9ccfd8ff).into()), + ("enum".into(), rgba(0xc4a7e6ff).into()), + ("boolean".into(), rgba(0xea9a97ff).into()), + ("punctuation.bracket".into(), rgba(0xaeabc6ff).into()), + ("operator".into(), rgba(0x3d8fb0ff).into()), + ("type".into(), rgba(0x9ccfd8ff).into()), + ("link_uri".into(), rgba(0xea9a97ff).into()), + ], + }, + status_bar: rgba(0x38354eff).into(), + title_bar: rgba(0x38354eff).into(), + toolbar: rgba(0x232136ff).into(), + tab_bar: rgba(0x28253cff).into(), + editor: rgba(0x232136ff).into(), + editor_subheader: rgba(0x28253cff).into(), + editor_active_line: rgba(0x28253cff).into(), + terminal: rgba(0x232136ff).into(), + image_fallback_background: rgba(0x38354eff).into(), + git_created: rgba(0x5cc1a3ff).into(), + git_modified: rgba(0x9bced6ff).into(), + git_deleted: rgba(0xea6e92ff).into(), + git_conflict: rgba(0xf5c177ff).into(), + git_ignored: rgba(0x605d7aff).into(), + git_renamed: rgba(0xf5c177ff).into(), + players: [ + PlayerTheme { + cursor: rgba(0x9bced6ff).into(), + selection: rgba(0x9bced63d).into(), + }, + PlayerTheme { + cursor: rgba(0x5cc1a3ff).into(), + selection: rgba(0x5cc1a33d).into(), + }, + PlayerTheme { + cursor: rgba(0xa683a0ff).into(), + selection: rgba(0xa683a03d).into(), + }, + PlayerTheme { + cursor: rgba(0xc4a7e6ff).into(), + selection: rgba(0xc4a7e63d).into(), + }, + PlayerTheme { + cursor: rgba(0xc4a7e6ff).into(), + selection: rgba(0xc4a7e63d).into(), + }, + PlayerTheme { + cursor: rgba(0x3e8fb0ff).into(), + selection: rgba(0x3e8fb03d).into(), + }, + PlayerTheme { + cursor: rgba(0xea6e92ff).into(), + selection: rgba(0xea6e923d).into(), + }, + PlayerTheme { + cursor: rgba(0xf5c177ff).into(), + selection: rgba(0xf5c1773d).into(), + }, + ], + } +} diff --git a/crates/theme2/src/themes/sandcastle.rs b/crates/theme2/src/themes/sandcastle.rs index 4e87c427f0..7fa0a27fb3 100644 --- a/crates/theme2/src/themes/sandcastle.rs +++ b/crates/theme2/src/themes/sandcastle.rs @@ -37,44 +37,44 @@ pub fn sandcastle() -> Theme { icon_muted: rgba(0xa69782ff).into(), syntax: SyntaxTheme { highlights: vec![ - ("string.special.symbol".into(), rgba(0xa07d3aff).into()), - ("enum".into(), rgba(0xa07d3aff).into()), + ("comment".into(), rgba(0xa89984ff).into()), + ("type".into(), rgba(0x83a598ff).into()), + ("preproc".into(), rgba(0xfdf4c1ff).into()), ("punctuation.bracket".into(), rgba(0xd5c5a1ff).into()), ("hint".into(), rgba(0x727d68ff).into()), - ("punctuation.delimiter".into(), rgba(0xd5c5a1ff).into()), - ("comment".into(), rgba(0xa89984ff).into()), - ("embedded".into(), rgba(0xfdf4c1ff).into()), + ("link_uri".into(), rgba(0x83a598ff).into()), + ("text.literal".into(), rgba(0xa07d3aff).into()), + ("enum".into(), rgba(0xa07d3aff).into()), + ("string.special".into(), rgba(0xa07d3aff).into()), ("string".into(), rgba(0xa07d3aff).into()), - ("string.escape".into(), rgba(0xa89984ff).into()), - ("comment.doc".into(), rgba(0xa89984ff).into()), - ("variant".into(), rgba(0x518b8bff).into()), + ("punctuation.special".into(), rgba(0xd5c5a1ff).into()), + ("keyword".into(), rgba(0x518b8bff).into()), + ("constructor".into(), rgba(0x518b8bff).into()), ("predictive".into(), rgba(0x5c6152ff).into()), - ("link_text".into(), rgba(0xa07d3aff).into()), - ("attribute".into(), rgba(0x518b8bff).into()), ("title".into(), rgba(0xfdf4c1ff).into()), + ("variable".into(), rgba(0xfdf4c1ff).into()), ("emphasis.strong".into(), rgba(0x518b8bff).into()), ("primary".into(), rgba(0xfdf4c1ff).into()), - ("punctuation.list_marker".into(), rgba(0xd5c5a1ff).into()), - ("boolean".into(), rgba(0x83a598ff).into()), - ("function".into(), rgba(0xa07d3aff).into()), - ("punctuation.special".into(), rgba(0xd5c5a1ff).into()), - ("string.special".into(), rgba(0xa07d3aff).into()), - ("string.regex".into(), rgba(0xa07d3aff).into()), - ("tag".into(), rgba(0x518b8bff).into()), - ("keyword".into(), rgba(0x518b8bff).into()), - ("type".into(), rgba(0x83a598ff).into()), - ("text.literal".into(), rgba(0xa07d3aff).into()), - ("link_uri".into(), rgba(0x83a598ff).into()), - ("label".into(), rgba(0x518b8bff).into()), - ("property".into(), rgba(0x518b8bff).into()), - ("number".into(), rgba(0x83a598ff).into()), - ("constructor".into(), rgba(0x518b8bff).into()), - ("preproc".into(), rgba(0xfdf4c1ff).into()), ("emphasis".into(), rgba(0x518b8bff).into()), - ("variable".into(), rgba(0xfdf4c1ff).into()), - ("operator".into(), rgba(0xa07d3aff).into()), ("punctuation".into(), rgba(0xd5c5a1ff).into()), ("constant".into(), rgba(0x83a598ff).into()), + ("link_text".into(), rgba(0xa07d3aff).into()), + ("punctuation.delimiter".into(), rgba(0xd5c5a1ff).into()), + ("embedded".into(), rgba(0xfdf4c1ff).into()), + ("string.special.symbol".into(), rgba(0xa07d3aff).into()), + ("tag".into(), rgba(0x518b8bff).into()), + ("punctuation.list_marker".into(), rgba(0xd5c5a1ff).into()), + ("operator".into(), rgba(0xa07d3aff).into()), + ("boolean".into(), rgba(0x83a598ff).into()), + ("function".into(), rgba(0xa07d3aff).into()), + ("attribute".into(), rgba(0x518b8bff).into()), + ("number".into(), rgba(0x83a598ff).into()), + ("string.escape".into(), rgba(0xa89984ff).into()), + ("comment.doc".into(), rgba(0xa89984ff).into()), + ("label".into(), rgba(0x518b8bff).into()), + ("string.regex".into(), rgba(0xa07d3aff).into()), + ("property".into(), rgba(0x518b8bff).into()), + ("variant".into(), rgba(0x518b8bff).into()), ], }, status_bar: rgba(0x333944ff).into(), diff --git a/crates/theme2/src/themes/solarized_dark.rs b/crates/theme2/src/themes/solarized_dark.rs new file mode 100644 index 0000000000..2e381a6e95 --- /dev/null +++ b/crates/theme2/src/themes/solarized_dark.rs @@ -0,0 +1,130 @@ +use gpui2::rgba; + +use crate::{PlayerTheme, SyntaxTheme, Theme, ThemeMetadata}; + +pub fn solarized_dark() -> Theme { + Theme { + metadata: ThemeMetadata { + name: "Solarized Dark".into(), + is_light: false, + }, + transparent: rgba(0x00000000).into(), + mac_os_traffic_light_red: rgba(0xec695eff).into(), + mac_os_traffic_light_yellow: rgba(0xf4bf4eff).into(), + mac_os_traffic_light_green: rgba(0x61c553ff).into(), + border: rgba(0x2b4e58ff).into(), + border_variant: rgba(0x2b4e58ff).into(), + border_focused: rgba(0x1b3149ff).into(), + border_transparent: rgba(0x00000000).into(), + elevated_surface: rgba(0x073743ff).into(), + surface: rgba(0x04313bff).into(), + background: rgba(0x073743ff).into(), + filled_element: rgba(0x073743ff).into(), + filled_element_hover: rgba(0xffffff1e).into(), + filled_element_active: rgba(0xffffff28).into(), + filled_element_selected: rgba(0x141f2cff).into(), + filled_element_disabled: rgba(0x00000000).into(), + ghost_element: rgba(0x00000000).into(), + ghost_element_hover: rgba(0xffffff14).into(), + ghost_element_active: rgba(0xffffff1e).into(), + ghost_element_selected: rgba(0x141f2cff).into(), + ghost_element_disabled: rgba(0x00000000).into(), + text: rgba(0xfdf6e3ff).into(), + text_muted: rgba(0x93a1a1ff).into(), + text_placeholder: rgba(0xdc3330ff).into(), + text_disabled: rgba(0x6f8389ff).into(), + text_accent: rgba(0x278ad1ff).into(), + icon_muted: rgba(0x93a1a1ff).into(), + syntax: SyntaxTheme { + highlights: vec![ + ("punctuation.special".into(), rgba(0xefe9d6ff).into()), + ("string".into(), rgba(0xcb4b16ff).into()), + ("variant".into(), rgba(0x278ad1ff).into()), + ("variable".into(), rgba(0xfdf6e3ff).into()), + ("string.special.symbol".into(), rgba(0xcb4b16ff).into()), + ("primary".into(), rgba(0xfdf6e3ff).into()), + ("type".into(), rgba(0x2ba198ff).into()), + ("boolean".into(), rgba(0x849903ff).into()), + ("string.special".into(), rgba(0xcb4b16ff).into()), + ("label".into(), rgba(0x278ad1ff).into()), + ("link_uri".into(), rgba(0x849903ff).into()), + ("constructor".into(), rgba(0x278ad1ff).into()), + ("hint".into(), rgba(0x4f8297ff).into()), + ("preproc".into(), rgba(0xfdf6e3ff).into()), + ("text.literal".into(), rgba(0xcb4b16ff).into()), + ("string.escape".into(), rgba(0x99a5a4ff).into()), + ("link_text".into(), rgba(0xcb4b16ff).into()), + ("comment".into(), rgba(0x99a5a4ff).into()), + ("enum".into(), rgba(0xcb4b16ff).into()), + ("constant".into(), rgba(0x849903ff).into()), + ("comment.doc".into(), rgba(0x99a5a4ff).into()), + ("emphasis".into(), rgba(0x278ad1ff).into()), + ("predictive".into(), rgba(0x3f718bff).into()), + ("attribute".into(), rgba(0x278ad1ff).into()), + ("punctuation.delimiter".into(), rgba(0xefe9d6ff).into()), + ("function".into(), rgba(0xb58902ff).into()), + ("emphasis.strong".into(), rgba(0x278ad1ff).into()), + ("tag".into(), rgba(0x278ad1ff).into()), + ("string.regex".into(), rgba(0xcb4b16ff).into()), + ("property".into(), rgba(0x278ad1ff).into()), + ("keyword".into(), rgba(0x278ad1ff).into()), + ("number".into(), rgba(0x849903ff).into()), + ("embedded".into(), rgba(0xfdf6e3ff).into()), + ("operator".into(), rgba(0xcb4b16ff).into()), + ("punctuation".into(), rgba(0xefe9d6ff).into()), + ("punctuation.bracket".into(), rgba(0xefe9d6ff).into()), + ("title".into(), rgba(0xfdf6e3ff).into()), + ("punctuation.list_marker".into(), rgba(0xefe9d6ff).into()), + ], + }, + status_bar: rgba(0x073743ff).into(), + title_bar: rgba(0x073743ff).into(), + toolbar: rgba(0x002a35ff).into(), + tab_bar: rgba(0x04313bff).into(), + editor: rgba(0x002a35ff).into(), + editor_subheader: rgba(0x04313bff).into(), + editor_active_line: rgba(0x04313bff).into(), + terminal: rgba(0x002a35ff).into(), + image_fallback_background: rgba(0x073743ff).into(), + git_created: rgba(0x849903ff).into(), + git_modified: rgba(0x278ad1ff).into(), + git_deleted: rgba(0xdc3330ff).into(), + git_conflict: rgba(0xb58902ff).into(), + git_ignored: rgba(0x6f8389ff).into(), + git_renamed: rgba(0xb58902ff).into(), + players: [ + PlayerTheme { + cursor: rgba(0x278ad1ff).into(), + selection: rgba(0x278ad13d).into(), + }, + PlayerTheme { + cursor: rgba(0x849903ff).into(), + selection: rgba(0x8499033d).into(), + }, + PlayerTheme { + cursor: rgba(0xd33781ff).into(), + selection: rgba(0xd337813d).into(), + }, + PlayerTheme { + cursor: rgba(0xcb4b16ff).into(), + selection: rgba(0xcb4b163d).into(), + }, + PlayerTheme { + cursor: rgba(0x6c71c4ff).into(), + selection: rgba(0x6c71c43d).into(), + }, + PlayerTheme { + cursor: rgba(0x2ba198ff).into(), + selection: rgba(0x2ba1983d).into(), + }, + PlayerTheme { + cursor: rgba(0xdc3330ff).into(), + selection: rgba(0xdc33303d).into(), + }, + PlayerTheme { + cursor: rgba(0xb58902ff).into(), + selection: rgba(0xb589023d).into(), + }, + ], + } +} diff --git a/crates/theme2/src/themes/solarized_light.rs b/crates/theme2/src/themes/solarized_light.rs new file mode 100644 index 0000000000..a959a0a9d1 --- /dev/null +++ b/crates/theme2/src/themes/solarized_light.rs @@ -0,0 +1,130 @@ +use gpui2::rgba; + +use crate::{PlayerTheme, SyntaxTheme, Theme, ThemeMetadata}; + +pub fn solarized_light() -> Theme { + Theme { + metadata: ThemeMetadata { + name: "Solarized Light".into(), + is_light: true, + }, + transparent: rgba(0x00000000).into(), + mac_os_traffic_light_red: rgba(0xec695eff).into(), + mac_os_traffic_light_yellow: rgba(0xf4bf4eff).into(), + mac_os_traffic_light_green: rgba(0x61c553ff).into(), + border: rgba(0x9faaa8ff).into(), + border_variant: rgba(0x9faaa8ff).into(), + border_focused: rgba(0xbfd3efff).into(), + border_transparent: rgba(0x00000000).into(), + elevated_surface: rgba(0xcfd0c4ff).into(), + surface: rgba(0xf3eddaff).into(), + background: rgba(0xcfd0c4ff).into(), + filled_element: rgba(0xcfd0c4ff).into(), + filled_element_hover: rgba(0xffffff1e).into(), + filled_element_active: rgba(0xffffff28).into(), + filled_element_selected: rgba(0xdbe6f6ff).into(), + filled_element_disabled: rgba(0x00000000).into(), + ghost_element: rgba(0x00000000).into(), + ghost_element_hover: rgba(0xffffff14).into(), + ghost_element_active: rgba(0xffffff1e).into(), + ghost_element_selected: rgba(0xdbe6f6ff).into(), + ghost_element_disabled: rgba(0x00000000).into(), + text: rgba(0x002a35ff).into(), + text_muted: rgba(0x34555eff).into(), + text_placeholder: rgba(0xdc3330ff).into(), + text_disabled: rgba(0x6a7f86ff).into(), + text_accent: rgba(0x288bd1ff).into(), + icon_muted: rgba(0x34555eff).into(), + syntax: SyntaxTheme { + highlights: vec![ + ("string.escape".into(), rgba(0x30525bff).into()), + ("boolean".into(), rgba(0x849903ff).into()), + ("comment.doc".into(), rgba(0x30525bff).into()), + ("string.special".into(), rgba(0xcb4b17ff).into()), + ("punctuation".into(), rgba(0x04333eff).into()), + ("emphasis".into(), rgba(0x288bd1ff).into()), + ("type".into(), rgba(0x2ba198ff).into()), + ("preproc".into(), rgba(0x002a35ff).into()), + ("emphasis.strong".into(), rgba(0x288bd1ff).into()), + ("constant".into(), rgba(0x849903ff).into()), + ("title".into(), rgba(0x002a35ff).into()), + ("operator".into(), rgba(0xcb4b17ff).into()), + ("punctuation.bracket".into(), rgba(0x04333eff).into()), + ("link_uri".into(), rgba(0x849903ff).into()), + ("label".into(), rgba(0x288bd1ff).into()), + ("enum".into(), rgba(0xcb4b17ff).into()), + ("property".into(), rgba(0x288bd1ff).into()), + ("predictive".into(), rgba(0x679aafff).into()), + ("punctuation.special".into(), rgba(0x04333eff).into()), + ("text.literal".into(), rgba(0xcb4b17ff).into()), + ("string".into(), rgba(0xcb4b17ff).into()), + ("string.regex".into(), rgba(0xcb4b17ff).into()), + ("variable".into(), rgba(0x002a35ff).into()), + ("tag".into(), rgba(0x288bd1ff).into()), + ("string.special.symbol".into(), rgba(0xcb4b17ff).into()), + ("link_text".into(), rgba(0xcb4b17ff).into()), + ("punctuation.list_marker".into(), rgba(0x04333eff).into()), + ("keyword".into(), rgba(0x288bd1ff).into()), + ("constructor".into(), rgba(0x288bd1ff).into()), + ("attribute".into(), rgba(0x288bd1ff).into()), + ("variant".into(), rgba(0x288bd1ff).into()), + ("function".into(), rgba(0xb58903ff).into()), + ("primary".into(), rgba(0x002a35ff).into()), + ("hint".into(), rgba(0x5789a3ff).into()), + ("comment".into(), rgba(0x30525bff).into()), + ("number".into(), rgba(0x849903ff).into()), + ("punctuation.delimiter".into(), rgba(0x04333eff).into()), + ("embedded".into(), rgba(0x002a35ff).into()), + ], + }, + status_bar: rgba(0xcfd0c4ff).into(), + title_bar: rgba(0xcfd0c4ff).into(), + toolbar: rgba(0xfdf6e3ff).into(), + tab_bar: rgba(0xf3eddaff).into(), + editor: rgba(0xfdf6e3ff).into(), + editor_subheader: rgba(0xf3eddaff).into(), + editor_active_line: rgba(0xf3eddaff).into(), + terminal: rgba(0xfdf6e3ff).into(), + image_fallback_background: rgba(0xcfd0c4ff).into(), + git_created: rgba(0x849903ff).into(), + git_modified: rgba(0x288bd1ff).into(), + git_deleted: rgba(0xdc3330ff).into(), + git_conflict: rgba(0xb58903ff).into(), + git_ignored: rgba(0x6a7f86ff).into(), + git_renamed: rgba(0xb58903ff).into(), + players: [ + PlayerTheme { + cursor: rgba(0x288bd1ff).into(), + selection: rgba(0x288bd13d).into(), + }, + PlayerTheme { + cursor: rgba(0x849903ff).into(), + selection: rgba(0x8499033d).into(), + }, + PlayerTheme { + cursor: rgba(0xd33781ff).into(), + selection: rgba(0xd337813d).into(), + }, + PlayerTheme { + cursor: rgba(0xcb4b17ff).into(), + selection: rgba(0xcb4b173d).into(), + }, + PlayerTheme { + cursor: rgba(0x6c71c3ff).into(), + selection: rgba(0x6c71c33d).into(), + }, + PlayerTheme { + cursor: rgba(0x2ba198ff).into(), + selection: rgba(0x2ba1983d).into(), + }, + PlayerTheme { + cursor: rgba(0xdc3330ff).into(), + selection: rgba(0xdc33303d).into(), + }, + PlayerTheme { + cursor: rgba(0xb58903ff).into(), + selection: rgba(0xb589033d).into(), + }, + ], + } +} diff --git a/crates/theme2/src/themes/summercamp.rs b/crates/theme2/src/themes/summercamp.rs new file mode 100644 index 0000000000..c1e66aedd1 --- /dev/null +++ b/crates/theme2/src/themes/summercamp.rs @@ -0,0 +1,130 @@ +use gpui2::rgba; + +use crate::{PlayerTheme, SyntaxTheme, Theme, ThemeMetadata}; + +pub fn summercamp() -> Theme { + Theme { + metadata: ThemeMetadata { + name: "Summercamp".into(), + is_light: false, + }, + transparent: rgba(0x00000000).into(), + mac_os_traffic_light_red: rgba(0xec695eff).into(), + mac_os_traffic_light_yellow: rgba(0xf4bf4eff).into(), + mac_os_traffic_light_green: rgba(0x61c553ff).into(), + border: rgba(0x302c21ff).into(), + border_variant: rgba(0x302c21ff).into(), + border_focused: rgba(0x193760ff).into(), + border_transparent: rgba(0x00000000).into(), + elevated_surface: rgba(0x2a261cff).into(), + surface: rgba(0x231f16ff).into(), + background: rgba(0x2a261cff).into(), + filled_element: rgba(0x2a261cff).into(), + filled_element_hover: rgba(0xffffff1e).into(), + filled_element_active: rgba(0xffffff28).into(), + filled_element_selected: rgba(0x0e2242ff).into(), + filled_element_disabled: rgba(0x00000000).into(), + ghost_element: rgba(0x00000000).into(), + ghost_element_hover: rgba(0xffffff14).into(), + ghost_element_active: rgba(0xffffff1e).into(), + ghost_element_selected: rgba(0x0e2242ff).into(), + ghost_element_disabled: rgba(0x00000000).into(), + text: rgba(0xf8f5deff).into(), + text_muted: rgba(0x736e55ff).into(), + text_placeholder: rgba(0xe35041ff).into(), + text_disabled: rgba(0x4c4735ff).into(), + text_accent: rgba(0x499befff).into(), + icon_muted: rgba(0x736e55ff).into(), + syntax: SyntaxTheme { + highlights: vec![ + ("predictive".into(), rgba(0x78434aff).into()), + ("title".into(), rgba(0xf8f5deff).into()), + ("primary".into(), rgba(0xf8f5deff).into()), + ("punctuation.special".into(), rgba(0xbfbb9bff).into()), + ("constant".into(), rgba(0x5dea5aff).into()), + ("string.regex".into(), rgba(0xfaa11cff).into()), + ("tag".into(), rgba(0x499befff).into()), + ("preproc".into(), rgba(0xf8f5deff).into()), + ("comment".into(), rgba(0x777159ff).into()), + ("punctuation.bracket".into(), rgba(0xbfbb9bff).into()), + ("constructor".into(), rgba(0x499befff).into()), + ("type".into(), rgba(0x5aeabbff).into()), + ("variable".into(), rgba(0xf8f5deff).into()), + ("operator".into(), rgba(0xfaa11cff).into()), + ("boolean".into(), rgba(0x5dea5aff).into()), + ("attribute".into(), rgba(0x499befff).into()), + ("link_text".into(), rgba(0xfaa11cff).into()), + ("string.escape".into(), rgba(0x777159ff).into()), + ("string.special".into(), rgba(0xfaa11cff).into()), + ("string.special.symbol".into(), rgba(0xfaa11cff).into()), + ("hint".into(), rgba(0x246e61ff).into()), + ("link_uri".into(), rgba(0x5dea5aff).into()), + ("comment.doc".into(), rgba(0x777159ff).into()), + ("emphasis".into(), rgba(0x499befff).into()), + ("punctuation".into(), rgba(0xbfbb9bff).into()), + ("text.literal".into(), rgba(0xfaa11cff).into()), + ("number".into(), rgba(0x5dea5aff).into()), + ("punctuation.delimiter".into(), rgba(0xbfbb9bff).into()), + ("label".into(), rgba(0x499befff).into()), + ("function".into(), rgba(0xf1fe28ff).into()), + ("property".into(), rgba(0x499befff).into()), + ("keyword".into(), rgba(0x499befff).into()), + ("embedded".into(), rgba(0xf8f5deff).into()), + ("string".into(), rgba(0xfaa11cff).into()), + ("punctuation.list_marker".into(), rgba(0xbfbb9bff).into()), + ("enum".into(), rgba(0xfaa11cff).into()), + ("emphasis.strong".into(), rgba(0x499befff).into()), + ("variant".into(), rgba(0x499befff).into()), + ], + }, + status_bar: rgba(0x2a261cff).into(), + title_bar: rgba(0x2a261cff).into(), + toolbar: rgba(0x1b1810ff).into(), + tab_bar: rgba(0x231f16ff).into(), + editor: rgba(0x1b1810ff).into(), + editor_subheader: rgba(0x231f16ff).into(), + editor_active_line: rgba(0x231f16ff).into(), + terminal: rgba(0x1b1810ff).into(), + image_fallback_background: rgba(0x2a261cff).into(), + git_created: rgba(0x5dea5aff).into(), + git_modified: rgba(0x499befff).into(), + git_deleted: rgba(0xe35041ff).into(), + git_conflict: rgba(0xf1fe28ff).into(), + git_ignored: rgba(0x4c4735ff).into(), + git_renamed: rgba(0xf1fe28ff).into(), + players: [ + PlayerTheme { + cursor: rgba(0x499befff).into(), + selection: rgba(0x499bef3d).into(), + }, + PlayerTheme { + cursor: rgba(0x5dea5aff).into(), + selection: rgba(0x5dea5a3d).into(), + }, + PlayerTheme { + cursor: rgba(0xf59be6ff).into(), + selection: rgba(0xf59be63d).into(), + }, + PlayerTheme { + cursor: rgba(0xfaa11cff).into(), + selection: rgba(0xfaa11c3d).into(), + }, + PlayerTheme { + cursor: rgba(0xfe8080ff).into(), + selection: rgba(0xfe80803d).into(), + }, + PlayerTheme { + cursor: rgba(0x5aeabbff).into(), + selection: rgba(0x5aeabb3d).into(), + }, + PlayerTheme { + cursor: rgba(0xe35041ff).into(), + selection: rgba(0xe350413d).into(), + }, + PlayerTheme { + cursor: rgba(0xf1fe28ff).into(), + selection: rgba(0xf1fe283d).into(), + }, + ], + } +} diff --git a/crates/theme_converter/Cargo.toml b/crates/theme_converter/Cargo.toml index 2a36dfce67..0ec692b7cc 100644 --- a/crates/theme_converter/Cargo.toml +++ b/crates/theme_converter/Cargo.toml @@ -9,6 +9,7 @@ publish = false [dependencies] anyhow.workspace = true clap = { version = "4.4", features = ["derive", "string"] } +convert_case = "0.6.0" gpui2 = { path = "../gpui2" } log.workspace = true rust-embed.workspace = true diff --git a/crates/theme_converter/src/main.rs b/crates/theme_converter/src/main.rs index 33a939d525..cc0cdf9c99 100644 --- a/crates/theme_converter/src/main.rs +++ b/crates/theme_converter/src/main.rs @@ -1,16 +1,25 @@ +mod theme_printer; + use std::borrow::Cow; use std::collections::HashMap; use std::fmt::{self, Debug}; +use std::fs::File; +use std::io::Write; +use std::path::PathBuf; +use std::str::FromStr; use anyhow::{anyhow, Context, Result}; use clap::Parser; -use gpui2::{hsla, rgb, serde_json, AssetSource, Hsla, Rgba, SharedString}; +use convert_case::{Case, Casing}; +use gpui2::{hsla, rgb, serde_json, AssetSource, Hsla, SharedString}; use log::LevelFilter; use rust_embed::RustEmbed; use serde::de::Visitor; use serde::{Deserialize, Deserializer}; use simplelog::SimpleLogger; -use theme2::{PlayerTheme, SyntaxTheme, ThemeMetadata}; +use theme2::{PlayerTheme, SyntaxTheme}; + +use crate::theme_printer::ThemePrinter; #[derive(Parser)] #[command(author, version, about, long_about = None)] @@ -22,13 +31,71 @@ struct Args { fn main() -> Result<()> { SimpleLogger::init(LevelFilter::Info, Default::default()).expect("could not initialize logger"); - let args = Args::parse(); + // let args = Args::parse(); - let (json_theme, legacy_theme) = load_theme(args.theme)?; + let themes_path = PathBuf::from_str("crates/theme2/src/themes")?; - let theme = convert_theme(json_theme, legacy_theme)?; + let mut theme_modules = Vec::new(); - println!("{:#?}", ThemePrinter(theme)); + for theme_path in Assets.list("themes/")? { + let (_, theme_name) = theme_path.split_once("themes/").unwrap(); + + if theme_name == ".gitkeep" { + continue; + } + + let (json_theme, legacy_theme) = load_theme(&theme_path)?; + + let theme = convert_theme(json_theme, legacy_theme)?; + + let theme_slug = theme + .metadata + .name + .as_ref() + .replace("é", "e") + .to_case(Case::Snake); + + let mut output_file = File::create(themes_path.join(format!("{theme_slug}.rs")))?; + + let theme_module = format!( + r#" + use gpui2::rgba; + + use crate::{{PlayerTheme, SyntaxTheme, Theme, ThemeMetadata}}; + + pub fn {theme_slug}() -> Theme {{ + {theme_definition} + }} + "#, + theme_definition = format!("{:#?}", ThemePrinter::new(theme)) + ); + + output_file.write_all(theme_module.as_bytes())?; + + theme_modules.push(theme_slug); + } + + let mut mod_rs_file = File::create(themes_path.join(format!("mod.rs")))?; + + let mod_rs_contents = format!( + r#" + {mod_statements} + + {use_statements} + "#, + mod_statements = theme_modules + .iter() + .map(|module| format!("mod {module};")) + .collect::>() + .join("\n"), + use_statements = theme_modules + .iter() + .map(|module| format!("pub use {module}::*;")) + .collect::>() + .join("\n") + ); + + mod_rs_file.write_all(mod_rs_contents.as_bytes())?; Ok(()) } @@ -184,9 +251,9 @@ struct JsonSyntaxStyle { } /// Loads the [`Theme`] with the given name. -fn load_theme(name: String) -> Result<(JsonTheme, LegacyTheme)> { - let theme_contents = Assets::get(&format!("themes/{name}.json")) - .with_context(|| format!("theme file not found: '{name}'"))?; +fn load_theme(theme_path: &str) -> Result<(JsonTheme, LegacyTheme)> { + let theme_contents = + Assets::get(theme_path).with_context(|| format!("theme file not found: '{theme_path}'"))?; let json_theme: JsonTheme = serde_json::from_str(std::str::from_utf8(&theme_contents.data)?) .context("failed to parse legacy theme")?; @@ -321,167 +388,3 @@ where } deserializer.deserialize_map(SyntaxVisitor) } - -pub struct ThemePrinter(theme2::Theme); - -struct HslaPrinter(Hsla); - -impl Debug for HslaPrinter { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", IntoPrinter(&Rgba::from(self.0))) - } -} - -struct IntoPrinter<'a, D: Debug>(&'a D); - -impl<'a, D: Debug> Debug for IntoPrinter<'a, D> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}.into()", self.0) - } -} - -impl Debug for ThemePrinter { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Theme") - .field("metadata", &ThemeMetadataPrinter(self.0.metadata.clone())) - .field("transparent", &HslaPrinter(self.0.transparent)) - .field( - "mac_os_traffic_light_red", - &HslaPrinter(self.0.mac_os_traffic_light_red), - ) - .field( - "mac_os_traffic_light_yellow", - &HslaPrinter(self.0.mac_os_traffic_light_yellow), - ) - .field( - "mac_os_traffic_light_green", - &HslaPrinter(self.0.mac_os_traffic_light_green), - ) - .field("border", &HslaPrinter(self.0.border)) - .field("border_variant", &HslaPrinter(self.0.border_variant)) - .field("border_focused", &HslaPrinter(self.0.border_focused)) - .field( - "border_transparent", - &HslaPrinter(self.0.border_transparent), - ) - .field("elevated_surface", &HslaPrinter(self.0.elevated_surface)) - .field("surface", &HslaPrinter(self.0.surface)) - .field("background", &HslaPrinter(self.0.background)) - .field("filled_element", &HslaPrinter(self.0.filled_element)) - .field( - "filled_element_hover", - &HslaPrinter(self.0.filled_element_hover), - ) - .field( - "filled_element_active", - &HslaPrinter(self.0.filled_element_active), - ) - .field( - "filled_element_selected", - &HslaPrinter(self.0.filled_element_selected), - ) - .field( - "filled_element_disabled", - &HslaPrinter(self.0.filled_element_disabled), - ) - .field("ghost_element", &HslaPrinter(self.0.ghost_element)) - .field( - "ghost_element_hover", - &HslaPrinter(self.0.ghost_element_hover), - ) - .field( - "ghost_element_active", - &HslaPrinter(self.0.ghost_element_active), - ) - .field( - "ghost_element_selected", - &HslaPrinter(self.0.ghost_element_selected), - ) - .field( - "ghost_element_disabled", - &HslaPrinter(self.0.ghost_element_disabled), - ) - .field("text", &HslaPrinter(self.0.text)) - .field("text_muted", &HslaPrinter(self.0.text_muted)) - .field("text_placeholder", &HslaPrinter(self.0.text_placeholder)) - .field("text_disabled", &HslaPrinter(self.0.text_disabled)) - .field("text_accent", &HslaPrinter(self.0.text_accent)) - .field("icon_muted", &HslaPrinter(self.0.icon_muted)) - .field("syntax", &SyntaxThemePrinter(self.0.syntax.clone())) - .field("status_bar", &HslaPrinter(self.0.status_bar)) - .field("title_bar", &HslaPrinter(self.0.title_bar)) - .field("toolbar", &HslaPrinter(self.0.toolbar)) - .field("tab_bar", &HslaPrinter(self.0.tab_bar)) - .field("editor", &HslaPrinter(self.0.editor)) - .field("editor_subheader", &HslaPrinter(self.0.editor_subheader)) - .field( - "editor_active_line", - &HslaPrinter(self.0.editor_active_line), - ) - .field("terminal", &HslaPrinter(self.0.terminal)) - .field( - "image_fallback_background", - &HslaPrinter(self.0.image_fallback_background), - ) - .field("git_created", &HslaPrinter(self.0.git_created)) - .field("git_modified", &HslaPrinter(self.0.git_modified)) - .field("git_deleted", &HslaPrinter(self.0.git_deleted)) - .field("git_conflict", &HslaPrinter(self.0.git_conflict)) - .field("git_ignored", &HslaPrinter(self.0.git_ignored)) - .field("git_renamed", &HslaPrinter(self.0.git_renamed)) - .field("players", &self.0.players.map(PlayerThemePrinter)) - .finish() - } -} - -pub struct ThemeMetadataPrinter(ThemeMetadata); - -impl Debug for ThemeMetadataPrinter { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("ThemeMetadata") - .field("name", &IntoPrinter(&self.0.name)) - .field("is_light", &self.0.is_light) - .finish() - } -} - -pub struct SyntaxThemePrinter(SyntaxTheme); - -impl Debug for SyntaxThemePrinter { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("SyntaxTheme") - .field( - "highlights", - &VecPrinter( - &self - .0 - .highlights - .iter() - .map(|(token, highlight)| { - (IntoPrinter(token), HslaPrinter(highlight.color.unwrap())) - }) - .collect(), - ), - ) - .finish() - } -} - -pub struct VecPrinter<'a, T>(&'a Vec); - -impl<'a, T: Debug> Debug for VecPrinter<'a, T> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "vec!{:?}", &self.0) - } -} - -pub struct PlayerThemePrinter(PlayerTheme); - -impl Debug for PlayerThemePrinter { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("PlayerTheme") - .field("cursor", &HslaPrinter(self.0.cursor)) - .field("selection", &HslaPrinter(self.0.selection)) - .finish() - } -} diff --git a/crates/theme_converter/src/theme_printer.rs b/crates/theme_converter/src/theme_printer.rs new file mode 100644 index 0000000000..3a9bdb159b --- /dev/null +++ b/crates/theme_converter/src/theme_printer.rs @@ -0,0 +1,174 @@ +use std::fmt::{self, Debug}; + +use gpui2::{Hsla, Rgba}; +use theme2::{PlayerTheme, SyntaxTheme, Theme, ThemeMetadata}; + +pub struct ThemePrinter(Theme); + +impl ThemePrinter { + pub fn new(theme: Theme) -> Self { + Self(theme) + } +} + +struct HslaPrinter(Hsla); + +impl Debug for HslaPrinter { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:?}", IntoPrinter(&Rgba::from(self.0))) + } +} + +struct IntoPrinter<'a, D: Debug>(&'a D); + +impl<'a, D: Debug> Debug for IntoPrinter<'a, D> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:?}.into()", self.0) + } +} + +impl Debug for ThemePrinter { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Theme") + .field("metadata", &ThemeMetadataPrinter(self.0.metadata.clone())) + .field("transparent", &HslaPrinter(self.0.transparent)) + .field( + "mac_os_traffic_light_red", + &HslaPrinter(self.0.mac_os_traffic_light_red), + ) + .field( + "mac_os_traffic_light_yellow", + &HslaPrinter(self.0.mac_os_traffic_light_yellow), + ) + .field( + "mac_os_traffic_light_green", + &HslaPrinter(self.0.mac_os_traffic_light_green), + ) + .field("border", &HslaPrinter(self.0.border)) + .field("border_variant", &HslaPrinter(self.0.border_variant)) + .field("border_focused", &HslaPrinter(self.0.border_focused)) + .field( + "border_transparent", + &HslaPrinter(self.0.border_transparent), + ) + .field("elevated_surface", &HslaPrinter(self.0.elevated_surface)) + .field("surface", &HslaPrinter(self.0.surface)) + .field("background", &HslaPrinter(self.0.background)) + .field("filled_element", &HslaPrinter(self.0.filled_element)) + .field( + "filled_element_hover", + &HslaPrinter(self.0.filled_element_hover), + ) + .field( + "filled_element_active", + &HslaPrinter(self.0.filled_element_active), + ) + .field( + "filled_element_selected", + &HslaPrinter(self.0.filled_element_selected), + ) + .field( + "filled_element_disabled", + &HslaPrinter(self.0.filled_element_disabled), + ) + .field("ghost_element", &HslaPrinter(self.0.ghost_element)) + .field( + "ghost_element_hover", + &HslaPrinter(self.0.ghost_element_hover), + ) + .field( + "ghost_element_active", + &HslaPrinter(self.0.ghost_element_active), + ) + .field( + "ghost_element_selected", + &HslaPrinter(self.0.ghost_element_selected), + ) + .field( + "ghost_element_disabled", + &HslaPrinter(self.0.ghost_element_disabled), + ) + .field("text", &HslaPrinter(self.0.text)) + .field("text_muted", &HslaPrinter(self.0.text_muted)) + .field("text_placeholder", &HslaPrinter(self.0.text_placeholder)) + .field("text_disabled", &HslaPrinter(self.0.text_disabled)) + .field("text_accent", &HslaPrinter(self.0.text_accent)) + .field("icon_muted", &HslaPrinter(self.0.icon_muted)) + .field("syntax", &SyntaxThemePrinter(self.0.syntax.clone())) + .field("status_bar", &HslaPrinter(self.0.status_bar)) + .field("title_bar", &HslaPrinter(self.0.title_bar)) + .field("toolbar", &HslaPrinter(self.0.toolbar)) + .field("tab_bar", &HslaPrinter(self.0.tab_bar)) + .field("editor", &HslaPrinter(self.0.editor)) + .field("editor_subheader", &HslaPrinter(self.0.editor_subheader)) + .field( + "editor_active_line", + &HslaPrinter(self.0.editor_active_line), + ) + .field("terminal", &HslaPrinter(self.0.terminal)) + .field( + "image_fallback_background", + &HslaPrinter(self.0.image_fallback_background), + ) + .field("git_created", &HslaPrinter(self.0.git_created)) + .field("git_modified", &HslaPrinter(self.0.git_modified)) + .field("git_deleted", &HslaPrinter(self.0.git_deleted)) + .field("git_conflict", &HslaPrinter(self.0.git_conflict)) + .field("git_ignored", &HslaPrinter(self.0.git_ignored)) + .field("git_renamed", &HslaPrinter(self.0.git_renamed)) + .field("players", &self.0.players.map(PlayerThemePrinter)) + .finish() + } +} + +pub struct ThemeMetadataPrinter(ThemeMetadata); + +impl Debug for ThemeMetadataPrinter { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("ThemeMetadata") + .field("name", &IntoPrinter(&self.0.name)) + .field("is_light", &self.0.is_light) + .finish() + } +} + +pub struct SyntaxThemePrinter(SyntaxTheme); + +impl Debug for SyntaxThemePrinter { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("SyntaxTheme") + .field( + "highlights", + &VecPrinter( + &self + .0 + .highlights + .iter() + .map(|(token, highlight)| { + (IntoPrinter(token), HslaPrinter(highlight.color.unwrap())) + }) + .collect(), + ), + ) + .finish() + } +} + +pub struct VecPrinter<'a, T>(&'a Vec); + +impl<'a, T: Debug> Debug for VecPrinter<'a, T> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "vec!{:?}", &self.0) + } +} + +pub struct PlayerThemePrinter(PlayerTheme); + +impl Debug for PlayerThemePrinter { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("PlayerTheme") + .field("cursor", &HslaPrinter(self.0.cursor)) + .field("selection", &HslaPrinter(self.0.selection)) + .finish() + } +} diff --git a/crates/ui2/src/components/assistant_panel.rs b/crates/ui2/src/components/assistant_panel.rs index 9b2abd5c17..51c123ad9e 100644 --- a/crates/ui2/src/components/assistant_panel.rs +++ b/crates/ui2/src/components/assistant_panel.rs @@ -1,7 +1,6 @@ -use gpui2::{rems, AbsoluteLength}; - use crate::prelude::*; use crate::{Icon, IconButton, Label, Panel, PanelSide}; +use gpui2::{rems, AbsoluteLength}; #[derive(Component)] pub struct AssistantPanel { @@ -76,15 +75,15 @@ pub use stories::*; #[cfg(feature = "stories")] mod stories { - use crate::Story; - use super::*; - - #[derive(Component)] + use crate::Story; + use gpui2::{Div, Render}; pub struct AssistantPanelStory; - impl AssistantPanelStory { - fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { + impl Render for AssistantPanelStory { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Self::Element { Story::container(cx) .child(Story::title_for::<_, AssistantPanel>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/breadcrumb.rs b/crates/ui2/src/components/breadcrumb.rs index 4a2cebcb80..6b2dfe1cce 100644 --- a/crates/ui2/src/components/breadcrumb.rs +++ b/crates/ui2/src/components/breadcrumb.rs @@ -73,21 +73,17 @@ pub use stories::*; #[cfg(feature = "stories")] mod stories { + use super::*; + use crate::Story; + use gpui2::Render; use std::str::FromStr; - use crate::Story; - - use super::*; - - #[derive(Component)] pub struct BreadcrumbStory; - impl BreadcrumbStory { - fn render( - self, - view_state: &mut V, - cx: &mut ViewContext, - ) -> impl Component { + impl Render for BreadcrumbStory { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Self::Element { let theme = theme(cx); Story::container(cx) diff --git a/crates/ui2/src/components/buffer.rs b/crates/ui2/src/components/buffer.rs index 5754397719..33a98b6ea9 100644 --- a/crates/ui2/src/components/buffer.rs +++ b/crates/ui2/src/components/buffer.rs @@ -233,20 +233,19 @@ pub use stories::*; #[cfg(feature = "stories")] mod stories { - use gpui2::rems; - + use super::*; use crate::{ empty_buffer_example, hello_world_rust_buffer_example, hello_world_rust_buffer_with_status_example, Story, }; + use gpui2::{rems, Div, Render}; - use super::*; - - #[derive(Component)] pub struct BufferStory; - impl BufferStory { - fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { + impl Render for BufferStory { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Self::Element { let theme = theme(cx); Story::container(cx) diff --git a/crates/ui2/src/components/buffer_search.rs b/crates/ui2/src/components/buffer_search.rs index fa7f752ffe..c5539f0a4a 100644 --- a/crates/ui2/src/components/buffer_search.rs +++ b/crates/ui2/src/components/buffer_search.rs @@ -1,4 +1,4 @@ -use gpui2::{AppContext, Context, View}; +use gpui2::{Div, Render, View, VisualContext}; use crate::prelude::*; use crate::{h_stack, Icon, IconButton, IconColor, Input}; @@ -21,15 +21,15 @@ impl BufferSearch { cx.notify(); } - pub fn view(cx: &mut AppContext) -> View { - { - let state = cx.entity(|cx| Self::new()); - let render = Self::render; - View::for_handle(state, render) - } + pub fn view(cx: &mut WindowContext) -> View { + cx.build_view(|cx| Self::new()) } +} - fn render(&mut self, cx: &mut ViewContext) -> impl Component { +impl Render for BufferSearch { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Div { let theme = theme(cx); h_stack().bg(theme.toolbar).p_2().child( diff --git a/crates/ui2/src/components/chat_panel.rs b/crates/ui2/src/components/chat_panel.rs index d4fddebc1b..f4f1ddf433 100644 --- a/crates/ui2/src/components/chat_panel.rs +++ b/crates/ui2/src/components/chat_panel.rs @@ -108,16 +108,18 @@ pub use stories::*; #[cfg(feature = "stories")] mod stories { use chrono::DateTime; + use gpui2::{Div, Render}; use crate::{Panel, Story}; use super::*; - #[derive(Component)] pub struct ChatPanelStory; - impl ChatPanelStory { - fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { + impl Render for ChatPanelStory { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Self::Element { Story::container(cx) .child(Story::title_for::<_, ChatPanel>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/collab_panel.rs b/crates/ui2/src/components/collab_panel.rs index d14c1fec1e..a8552c0f23 100644 --- a/crates/ui2/src/components/collab_panel.rs +++ b/crates/ui2/src/components/collab_panel.rs @@ -89,15 +89,16 @@ pub use stories::*; #[cfg(feature = "stories")] mod stories { - use crate::Story; - use super::*; + use crate::Story; + use gpui2::{Div, Render}; - #[derive(Component)] pub struct CollabPanelStory; - impl CollabPanelStory { - fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { + impl Render for CollabPanelStory { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Self::Element { Story::container(cx) .child(Story::title_for::<_, CollabPanel>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/command_palette.rs b/crates/ui2/src/components/command_palette.rs index 71ca5bc41b..63db4359e7 100644 --- a/crates/ui2/src/components/command_palette.rs +++ b/crates/ui2/src/components/command_palette.rs @@ -27,15 +27,18 @@ pub use stories::*; #[cfg(feature = "stories")] mod stories { + use gpui2::{Div, Render}; + use crate::Story; use super::*; - #[derive(Component)] pub struct CommandPaletteStory; - impl CommandPaletteStory { - fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { + impl Render for CommandPaletteStory { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Self::Element { Story::container(cx) .child(Story::title_for::<_, CommandPalette>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/context_menu.rs b/crates/ui2/src/components/context_menu.rs index f2a5557f17..812221036a 100644 --- a/crates/ui2/src/components/context_menu.rs +++ b/crates/ui2/src/components/context_menu.rs @@ -68,15 +68,16 @@ pub use stories::*; #[cfg(feature = "stories")] mod stories { - use crate::story::Story; - use super::*; + use crate::story::Story; + use gpui2::{Div, Render}; - #[derive(Component)] pub struct ContextMenuStory; - impl ContextMenuStory { - fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { + impl Render for ContextMenuStory { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Self::Element { Story::container(cx) .child(Story::title_for::<_, ContextMenu>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/copilot.rs b/crates/ui2/src/components/copilot.rs index 7a565d0907..51523d48f0 100644 --- a/crates/ui2/src/components/copilot.rs +++ b/crates/ui2/src/components/copilot.rs @@ -25,15 +25,18 @@ pub use stories::*; #[cfg(feature = "stories")] mod stories { + use gpui2::{Div, Render}; + use crate::Story; use super::*; - #[derive(Component)] pub struct CopilotModalStory; - impl CopilotModalStory { - fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { + impl Render for CopilotModalStory { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Self::Element { Story::container(cx) .child(Story::title_for::<_, CopilotModal>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/editor_pane.rs b/crates/ui2/src/components/editor_pane.rs index ec73bb805f..8e54d2c2e8 100644 --- a/crates/ui2/src/components/editor_pane.rs +++ b/crates/ui2/src/components/editor_pane.rs @@ -1,6 +1,6 @@ use std::path::PathBuf; -use gpui2::{AppContext, Context, View}; +use gpui2::{Div, Render, View, VisualContext}; use crate::prelude::*; use crate::{ @@ -20,7 +20,7 @@ pub struct EditorPane { impl EditorPane { pub fn new( - cx: &mut AppContext, + cx: &mut ViewContext, tabs: Vec, path: PathBuf, symbols: Vec, @@ -42,15 +42,15 @@ impl EditorPane { cx.notify(); } - pub fn view(cx: &mut AppContext) -> View { - { - let state = cx.entity(|cx| hello_world_rust_editor_with_status_example(cx)); - let render = Self::render; - View::for_handle(state, render) - } + pub fn view(cx: &mut WindowContext) -> View { + cx.build_view(|cx| hello_world_rust_editor_with_status_example(cx)) } +} - fn render(&mut self, cx: &mut ViewContext) -> impl Component { +impl Render for EditorPane { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Div { v_stack() .w_full() .h_full() diff --git a/crates/ui2/src/components/facepile.rs b/crates/ui2/src/components/facepile.rs index ab1ae47139..21dd848a28 100644 --- a/crates/ui2/src/components/facepile.rs +++ b/crates/ui2/src/components/facepile.rs @@ -31,15 +31,16 @@ pub use stories::*; #[cfg(feature = "stories")] mod stories { - use crate::{static_players, Story}; - use super::*; + use crate::{static_players, Story}; + use gpui2::{Div, Render}; - #[derive(Component)] pub struct FacepileStory; - impl FacepileStory { - fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { + impl Render for FacepileStory { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Self::Element { let players = static_players(); Story::container(cx) diff --git a/crates/ui2/src/components/keybinding.rs b/crates/ui2/src/components/keybinding.rs index ec29e7a95d..455cfe5b59 100644 --- a/crates/ui2/src/components/keybinding.rs +++ b/crates/ui2/src/components/keybinding.rs @@ -158,17 +158,17 @@ pub use stories::*; #[cfg(feature = "stories")] mod stories { + use super::*; + use crate::Story; + use gpui2::{Div, Render}; use itertools::Itertools; - use crate::Story; - - use super::*; - - #[derive(Component)] pub struct KeybindingStory; - impl KeybindingStory { - fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { + impl Render for KeybindingStory { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Self::Element { let all_modifier_permutations = ModifierKey::iter().permutations(2); Story::container(cx) diff --git a/crates/ui2/src/components/language_selector.rs b/crates/ui2/src/components/language_selector.rs index f75dcf3eaf..fa7f5b2bd7 100644 --- a/crates/ui2/src/components/language_selector.rs +++ b/crates/ui2/src/components/language_selector.rs @@ -38,15 +38,16 @@ pub use stories::*; #[cfg(feature = "stories")] mod stories { - use crate::Story; - use super::*; + use crate::Story; + use gpui2::{Div, Render}; - #[derive(Component)] pub struct LanguageSelectorStory; - impl LanguageSelectorStory { - fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { + impl Render for LanguageSelectorStory { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Self::Element { Story::container(cx) .child(Story::title_for::<_, LanguageSelector>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/multi_buffer.rs b/crates/ui2/src/components/multi_buffer.rs index e5051fc5b8..696fc77a62 100644 --- a/crates/ui2/src/components/multi_buffer.rs +++ b/crates/ui2/src/components/multi_buffer.rs @@ -40,15 +40,16 @@ pub use stories::*; #[cfg(feature = "stories")] mod stories { - use crate::{hello_world_rust_buffer_example, Story}; - use super::*; + use crate::{hello_world_rust_buffer_example, Story}; + use gpui2::{Div, Render}; - #[derive(Component)] pub struct MultiBufferStory; - impl MultiBufferStory { - fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { + impl Render for MultiBufferStory { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Self::Element { let theme = theme(cx); Story::container(cx) diff --git a/crates/ui2/src/components/notifications_panel.rs b/crates/ui2/src/components/notifications_panel.rs index 68fe6d4bd0..6872f116e9 100644 --- a/crates/ui2/src/components/notifications_panel.rs +++ b/crates/ui2/src/components/notifications_panel.rs @@ -48,15 +48,16 @@ pub use stories::*; #[cfg(feature = "stories")] mod stories { - use crate::{Panel, Story}; - use super::*; + use crate::{Panel, Story}; + use gpui2::{Div, Render}; - #[derive(Component)] pub struct NotificationsPanelStory; - impl NotificationsPanelStory { - fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { + impl Render for NotificationsPanelStory { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Self::Element { Story::container(cx) .child(Story::title_for::<_, NotificationsPanel>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/palette.rs b/crates/ui2/src/components/palette.rs index a74c9e3672..e47f6a4cea 100644 --- a/crates/ui2/src/components/palette.rs +++ b/crates/ui2/src/components/palette.rs @@ -152,58 +152,71 @@ pub use stories::*; #[cfg(feature = "stories")] mod stories { + use gpui2::{Div, Render}; + use crate::{ModifierKeys, Story}; use super::*; - #[derive(Component)] pub struct PaletteStory; - impl PaletteStory { - fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { - Story::container(cx) - .child(Story::title_for::<_, Palette>(cx)) - .child(Story::label(cx, "Default")) - .child(Palette::new("palette-1")) - .child(Story::label(cx, "With Items")) - .child( - Palette::new("palette-2") - .placeholder("Execute a command...") - .items(vec![ - PaletteItem::new("theme selector: toggle").keybinding( - Keybinding::new_chord( - ("k".to_string(), ModifierKeys::new().command(true)), - ("t".to_string(), ModifierKeys::new().command(true)), + impl Render for PaletteStory { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Self::Element { + { + Story::container(cx) + .child(Story::title_for::<_, Palette>(cx)) + .child(Story::label(cx, "Default")) + .child(Palette::new("palette-1")) + .child(Story::label(cx, "With Items")) + .child( + Palette::new("palette-2") + .placeholder("Execute a command...") + .items(vec![ + PaletteItem::new("theme selector: toggle").keybinding( + Keybinding::new_chord( + ("k".to_string(), ModifierKeys::new().command(true)), + ("t".to_string(), ModifierKeys::new().command(true)), + ), ), - ), - PaletteItem::new("assistant: inline assist").keybinding( - Keybinding::new( - "enter".to_string(), - ModifierKeys::new().command(true), + PaletteItem::new("assistant: inline assist").keybinding( + Keybinding::new( + "enter".to_string(), + ModifierKeys::new().command(true), + ), ), - ), - PaletteItem::new("assistant: quote selection").keybinding( - Keybinding::new(">".to_string(), ModifierKeys::new().command(true)), - ), - PaletteItem::new("assistant: toggle focus").keybinding( - Keybinding::new("?".to_string(), ModifierKeys::new().command(true)), - ), - PaletteItem::new("auto update: check"), - PaletteItem::new("auto update: view release notes"), - PaletteItem::new("branches: open recent").keybinding(Keybinding::new( - "b".to_string(), - ModifierKeys::new().command(true).alt(true), - )), - PaletteItem::new("chat panel: toggle focus"), - PaletteItem::new("cli: install"), - PaletteItem::new("client: sign in"), - PaletteItem::new("client: sign out"), - PaletteItem::new("editor: cancel").keybinding(Keybinding::new( - "escape".to_string(), - ModifierKeys::new(), - )), - ]), - ) + PaletteItem::new("assistant: quote selection").keybinding( + Keybinding::new( + ">".to_string(), + ModifierKeys::new().command(true), + ), + ), + PaletteItem::new("assistant: toggle focus").keybinding( + Keybinding::new( + "?".to_string(), + ModifierKeys::new().command(true), + ), + ), + PaletteItem::new("auto update: check"), + PaletteItem::new("auto update: view release notes"), + PaletteItem::new("branches: open recent").keybinding( + Keybinding::new( + "b".to_string(), + ModifierKeys::new().command(true).alt(true), + ), + ), + PaletteItem::new("chat panel: toggle focus"), + PaletteItem::new("cli: install"), + PaletteItem::new("client: sign in"), + PaletteItem::new("client: sign out"), + PaletteItem::new("editor: cancel").keybinding(Keybinding::new( + "escape".to_string(), + ModifierKeys::new(), + )), + ]), + ) + } } } } diff --git a/crates/ui2/src/components/panel.rs b/crates/ui2/src/components/panel.rs index 40129dbd76..12d2207ffd 100644 --- a/crates/ui2/src/components/panel.rs +++ b/crates/ui2/src/components/panel.rs @@ -128,17 +128,18 @@ pub use stories::*; #[cfg(feature = "stories")] mod stories { - use crate::{Label, Story}; - use super::*; + use crate::{Label, Story}; + use gpui2::{Div, Render}; - #[derive(Component)] pub struct PanelStory; - impl PanelStory { - fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { + impl Render for PanelStory { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Self::Element { Story::container(cx) - .child(Story::title_for::<_, Panel>(cx)) + .child(Story::title_for::<_, Panel>(cx)) .child(Story::label(cx, "Default")) .child( Panel::new("panel", cx).child( diff --git a/crates/ui2/src/components/panes.rs b/crates/ui2/src/components/panes.rs index b692872741..854786ebaa 100644 --- a/crates/ui2/src/components/panes.rs +++ b/crates/ui2/src/components/panes.rs @@ -1,4 +1,4 @@ -use gpui2::{hsla, red, AnyElement, ElementId, ExternalPaths, Hsla, Length, Size}; +use gpui2::{hsla, red, AnyElement, ElementId, ExternalPaths, Hsla, Length, Size, View}; use smallvec::SmallVec; use crate::prelude::*; @@ -18,13 +18,6 @@ pub struct Pane { children: SmallVec<[AnyElement; 2]>, } -// impl IntoAnyElement for Pane { -// fn into_any(self) -> AnyElement { -// (move |view_state: &mut V, cx: &mut ViewContext<'_, '_, V>| self.render(view_state, cx)) -// .into_any() -// } -// } - impl Pane { pub fn new(id: impl Into, size: Size) -> Self { // Fill is only here for debugging purposes, remove before release @@ -57,8 +50,8 @@ impl Pane { .z_index(1) .id("drag-target") .drag_over::(|d| d.bg(red())) - .on_drop(|_, files: ExternalPaths, _| { - dbg!("dropped files!", files); + .on_drop(|_, files: View, cx| { + dbg!("dropped files!", files.read(cx)); }) .absolute() .inset_0(), diff --git a/crates/ui2/src/components/project_panel.rs b/crates/ui2/src/components/project_panel.rs index 9f15102acc..84c68119fe 100644 --- a/crates/ui2/src/components/project_panel.rs +++ b/crates/ui2/src/components/project_panel.rs @@ -57,15 +57,16 @@ pub use stories::*; #[cfg(feature = "stories")] mod stories { - use crate::{Panel, Story}; - use super::*; + use crate::{Panel, Story}; + use gpui2::{Div, Render}; - #[derive(Component)] pub struct ProjectPanelStory; - impl ProjectPanelStory { - fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { + impl Render for ProjectPanelStory { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Self::Element { Story::container(cx) .child(Story::title_for::<_, ProjectPanel>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/recent_projects.rs b/crates/ui2/src/components/recent_projects.rs index cd7c22eecb..d5a9dd1b22 100644 --- a/crates/ui2/src/components/recent_projects.rs +++ b/crates/ui2/src/components/recent_projects.rs @@ -34,15 +34,16 @@ pub use stories::*; #[cfg(feature = "stories")] mod stories { - use crate::Story; - use super::*; + use crate::Story; + use gpui2::{Div, Render}; - #[derive(Component)] pub struct RecentProjectsStory; - impl RecentProjectsStory { - fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { + impl Render for RecentProjectsStory { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Self::Element { Story::container(cx) .child(Story::title_for::<_, RecentProjects>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/tab.rs b/crates/ui2/src/components/tab.rs index 6133906f27..d784ec0174 100644 --- a/crates/ui2/src/components/tab.rs +++ b/crates/ui2/src/components/tab.rs @@ -1,5 +1,6 @@ use crate::prelude::*; use crate::{Icon, IconColor, IconElement, Label, LabelColor}; +use gpui2::{black, red, Div, ElementId, Render, View, VisualContext}; #[derive(Component, Clone)] pub struct Tab { @@ -19,6 +20,14 @@ struct TabDragState { title: String, } +impl Render for TabDragState { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Self::Element { + div().w_8().h_4().bg(red()) + } +} + impl Tab { pub fn new(id: impl Into) -> Self { Self { @@ -118,12 +127,10 @@ impl Tab { div() .id(self.id.clone()) - .on_drag(move |_view, _cx| { - Drag::new(drag_state.clone(), |view, cx| div().w_8().h_4().bg(red())) - }) + .on_drag(move |_view, cx| cx.build_view(|cx| drag_state.clone())) .drag_over::(|d| d.bg(black())) - .on_drop(|_view, state: TabDragState, cx| { - dbg!(state); + .on_drop(|_view, state: View, cx| { + dbg!(state.read(cx)); }) .px_2() .py_0p5() @@ -160,23 +167,21 @@ impl Tab { } } -use gpui2::{black, red, Drag, ElementId}; #[cfg(feature = "stories")] pub use stories::*; #[cfg(feature = "stories")] mod stories { + use super::*; + use crate::{h_stack, v_stack, Icon, Story}; use strum::IntoEnumIterator; - use crate::{h_stack, v_stack, Icon, Story}; - - use super::*; - - #[derive(Component)] pub struct TabStory; - impl TabStory { - fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { + impl Render for TabStory { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Self::Element { let git_statuses = GitStatus::iter(); let fs_statuses = FileSystemStatus::iter(); diff --git a/crates/ui2/src/components/tab_bar.rs b/crates/ui2/src/components/tab_bar.rs index cffdc09026..da0a41a1bf 100644 --- a/crates/ui2/src/components/tab_bar.rs +++ b/crates/ui2/src/components/tab_bar.rs @@ -92,15 +92,16 @@ pub use stories::*; #[cfg(feature = "stories")] mod stories { - use crate::Story; - use super::*; + use crate::Story; + use gpui2::{Div, Render}; - #[derive(Component)] pub struct TabBarStory; - impl TabBarStory { - fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { + impl Render for TabBarStory { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Self::Element { Story::container(cx) .child(Story::title_for::<_, TabBar>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/terminal.rs b/crates/ui2/src/components/terminal.rs index b7c8c5d75d..a751d47dfc 100644 --- a/crates/ui2/src/components/terminal.rs +++ b/crates/ui2/src/components/terminal.rs @@ -83,15 +83,15 @@ pub use stories::*; #[cfg(feature = "stories")] mod stories { - use crate::Story; - use super::*; - - #[derive(Component)] + use crate::Story; + use gpui2::{Div, Render}; pub struct TerminalStory; - impl TerminalStory { - fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { + impl Render for TerminalStory { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Self::Element { Story::container(cx) .child(Story::title_for::<_, Terminal>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/theme_selector.rs b/crates/ui2/src/components/theme_selector.rs index b5fcd17d2f..5c67f1cd3e 100644 --- a/crates/ui2/src/components/theme_selector.rs +++ b/crates/ui2/src/components/theme_selector.rs @@ -39,15 +39,18 @@ pub use stories::*; #[cfg(feature = "stories")] mod stories { + use gpui2::{Div, Render}; + use crate::Story; use super::*; - #[derive(Component)] pub struct ThemeSelectorStory; - impl ThemeSelectorStory { - fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { + impl Render for ThemeSelectorStory { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Self::Element { Story::container(cx) .child(Story::title_for::<_, ThemeSelector>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/title_bar.rs b/crates/ui2/src/components/title_bar.rs index 11dd1b99f6..4b3b125dea 100644 --- a/crates/ui2/src/components/title_bar.rs +++ b/crates/ui2/src/components/title_bar.rs @@ -1,7 +1,7 @@ use std::sync::atomic::AtomicBool; use std::sync::Arc; -use gpui2::{AppContext, Context, ModelContext, View}; +use gpui2::{Div, Render, View, VisualContext}; use crate::prelude::*; use crate::settings::user_settings; @@ -28,7 +28,7 @@ pub struct TitleBar { } impl TitleBar { - pub fn new(cx: &mut ModelContext) -> Self { + pub fn new(cx: &mut ViewContext) -> Self { let is_active = Arc::new(AtomicBool::new(true)); let active = is_active.clone(); @@ -80,15 +80,15 @@ impl TitleBar { cx.notify(); } - pub fn view(cx: &mut AppContext, livestream: Option) -> View { - { - let state = cx.entity(|cx| Self::new(cx).set_livestream(livestream)); - let render = Self::render; - View::for_handle(state, render) - } + pub fn view(cx: &mut WindowContext, livestream: Option) -> View { + cx.build_view(|cx| Self::new(cx).set_livestream(livestream)) } +} - fn render(&mut self, cx: &mut ViewContext) -> impl Component { +impl Render for TitleBar { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Div { let theme = theme(cx); let settings = user_settings(cx); @@ -187,26 +187,25 @@ pub use stories::*; #[cfg(feature = "stories")] mod stories { - use crate::Story; - use super::*; + use crate::Story; pub struct TitleBarStory { title_bar: View, } impl TitleBarStory { - pub fn view(cx: &mut AppContext) -> View { - { - let state = cx.entity(|cx| Self { - title_bar: TitleBar::view(cx, None), - }); - let render = Self::render; - View::for_handle(state, render) - } + pub fn view(cx: &mut WindowContext) -> View { + cx.build_view(|cx| Self { + title_bar: TitleBar::view(cx, None), + }) } + } - fn render(&mut self, cx: &mut ViewContext) -> impl Component { + impl Render for TitleBarStory { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Div { Story::container(cx) .child(Story::title_for::<_, TitleBar>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/toast.rs b/crates/ui2/src/components/toast.rs index dca6f7c28a..814e91c498 100644 --- a/crates/ui2/src/components/toast.rs +++ b/crates/ui2/src/components/toast.rs @@ -72,17 +72,20 @@ pub use stories::*; #[cfg(feature = "stories")] mod stories { + use gpui2::{Div, Render}; + use crate::{Label, Story}; use super::*; - #[derive(Component)] pub struct ToastStory; - impl ToastStory { - fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { + impl Render for ToastStory { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Self::Element { Story::container(cx) - .child(Story::title_for::<_, Toast>(cx)) + .child(Story::title_for::<_, Toast>(cx)) .child(Story::label(cx, "Default")) .child(Toast::new(ToastOrigin::Bottom).child(Label::new("label"))) } diff --git a/crates/ui2/src/components/toolbar.rs b/crates/ui2/src/components/toolbar.rs index a833090c1c..4b35e2d9d2 100644 --- a/crates/ui2/src/components/toolbar.rs +++ b/crates/ui2/src/components/toolbar.rs @@ -75,19 +75,22 @@ mod stories { use std::path::PathBuf; use std::str::FromStr; + use gpui2::{Div, Render}; + use crate::{Breadcrumb, HighlightedText, Icon, IconButton, Story, Symbol}; use super::*; - #[derive(Component)] pub struct ToolbarStory; - impl ToolbarStory { - fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { + impl Render for ToolbarStory { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Self::Element { let theme = theme(cx); Story::container(cx) - .child(Story::title_for::<_, Toolbar>(cx)) + .child(Story::title_for::<_, Toolbar>(cx)) .child(Story::label(cx, "Default")) .child( Toolbar::new() diff --git a/crates/ui2/src/components/traffic_lights.rs b/crates/ui2/src/components/traffic_lights.rs index 320e7e68fd..8ee19d26f5 100644 --- a/crates/ui2/src/components/traffic_lights.rs +++ b/crates/ui2/src/components/traffic_lights.rs @@ -77,15 +77,18 @@ pub use stories::*; #[cfg(feature = "stories")] mod stories { + use gpui2::{Div, Render}; + use crate::Story; use super::*; - #[derive(Component)] pub struct TrafficLightsStory; - impl TrafficLightsStory { - fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { + impl Render for TrafficLightsStory { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Self::Element { Story::container(cx) .child(Story::title_for::<_, TrafficLights>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/components/workspace.rs b/crates/ui2/src/components/workspace.rs index fbb2c64668..78ab6232a8 100644 --- a/crates/ui2/src/components/workspace.rs +++ b/crates/ui2/src/components/workspace.rs @@ -1,15 +1,15 @@ use std::sync::Arc; use chrono::DateTime; -use gpui2::{px, relative, rems, AppContext, Context, Size, View}; +use gpui2::{px, relative, rems, Div, Render, Size, View, VisualContext}; -use crate::{ - old_theme, static_livestream, user_settings_mut, v_stack, AssistantPanel, Button, ChatMessage, - ChatPanel, CollabPanel, EditorPane, FakeSettings, Label, LanguageSelector, Pane, PaneGroup, - Panel, PanelAllowedSides, PanelSide, ProjectPanel, SettingValue, SplitDirection, StatusBar, - Terminal, TitleBar, Toast, ToastOrigin, -}; use crate::{prelude::*, NotificationsPanel}; +use crate::{ + static_livestream, user_settings_mut, v_stack, AssistantPanel, Button, ChatMessage, ChatPanel, + CollabPanel, EditorPane, FakeSettings, Label, LanguageSelector, Pane, PaneGroup, Panel, + PanelAllowedSides, PanelSide, ProjectPanel, SettingValue, SplitDirection, StatusBar, Terminal, + TitleBar, Toast, ToastOrigin, +}; #[derive(Clone)] pub struct Gpui2UiDebug { @@ -44,7 +44,7 @@ pub struct Workspace { } impl Workspace { - pub fn new(cx: &mut AppContext) -> Self { + pub fn new(cx: &mut ViewContext) -> Self { Self { title_bar: TitleBar::view(cx, None), editor_1: EditorPane::view(cx), @@ -170,16 +170,16 @@ impl Workspace { cx.notify(); } - pub fn view(cx: &mut AppContext) -> View { - { - let state = cx.entity(|cx| Self::new(cx)); - let render = Self::render; - View::for_handle(state, render) - } + pub fn view(cx: &mut WindowContext) -> View { + cx.build_view(|cx| Self::new(cx)) } +} - pub fn render(&mut self, cx: &mut ViewContext) -> impl Component { - let theme = old_theme(cx).clone(); +impl Render for Workspace { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Div { + let theme = theme(cx); // HACK: This should happen inside of `debug_toggle_user_settings`, but // we don't have `cx.global::()` in event handlers at the moment. @@ -216,8 +216,8 @@ impl Workspace { .gap_0() .justify_start() .items_start() - .text_color(theme.lowest.base.default.foreground) - .bg(theme.lowest.base.default.background) + .text_color(theme.text) + .bg(theme.background) .child(self.title_bar.clone()) .child( div() @@ -228,7 +228,7 @@ impl Workspace { .overflow_hidden() .border_t() .border_b() - .border_color(theme.lowest.base.default.border) + .border_color(theme.border) .children( Some( Panel::new("project-panel-outer", cx) @@ -355,9 +355,8 @@ pub use stories::*; #[cfg(feature = "stories")] mod stories { - use gpui2::VisualContext; - use super::*; + use gpui2::VisualContext; pub struct WorkspaceStory { workspace: View, @@ -365,12 +364,17 @@ mod stories { impl WorkspaceStory { pub fn view(cx: &mut WindowContext) -> View { - cx.build_view( - |cx| Self { - workspace: Workspace::view(cx), - }, - |view, cx| view.workspace.clone(), - ) + cx.build_view(|cx| Self { + workspace: Workspace::view(cx), + }) + } + } + + impl Render for WorkspaceStory { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Self::Element { + div().child(self.workspace.clone()) } } } diff --git a/crates/ui2/src/elements/avatar.rs b/crates/ui2/src/elements/avatar.rs index 87133209a2..f008eeb479 100644 --- a/crates/ui2/src/elements/avatar.rs +++ b/crates/ui2/src/elements/avatar.rs @@ -43,15 +43,16 @@ pub use stories::*; #[cfg(feature = "stories")] mod stories { - use crate::Story; - use super::*; + use crate::Story; + use gpui2::{Div, Render}; - #[derive(Component)] pub struct AvatarStory; - impl AvatarStory { - fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { + impl Render for AvatarStory { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Self::Element { Story::container(cx) .child(Story::title_for::<_, Avatar>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/elements/button.rs b/crates/ui2/src/elements/button.rs index 15d65dc5d2..d27a0537d8 100644 --- a/crates/ui2/src/elements/button.rs +++ b/crates/ui2/src/elements/button.rs @@ -219,22 +219,21 @@ pub use stories::*; #[cfg(feature = "stories")] mod stories { - use gpui2::rems; + use super::*; + use crate::{h_stack, v_stack, LabelColor, Story}; + use gpui2::{rems, Div, Render}; use strum::IntoEnumIterator; - use crate::{h_stack, v_stack, LabelColor, Story}; - - use super::*; - - #[derive(Component)] pub struct ButtonStory; - impl ButtonStory { - fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { + impl Render for ButtonStory { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Self::Element { let states = InteractionState::iter(); Story::container(cx) - .child(Story::title_for::<_, Button>(cx)) + .child(Story::title_for::<_, Button>(cx)) .child( div() .flex() diff --git a/crates/ui2/src/elements/details.rs b/crates/ui2/src/elements/details.rs index f89cfb53db..eca7798c82 100644 --- a/crates/ui2/src/elements/details.rs +++ b/crates/ui2/src/elements/details.rs @@ -46,17 +46,18 @@ pub use stories::*; #[cfg(feature = "stories")] mod stories { - use crate::{Button, Story}; - use super::*; + use crate::{Button, Story}; + use gpui2::{Div, Render}; - #[derive(Component)] pub struct DetailsStory; - impl DetailsStory { - fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { + impl Render for DetailsStory { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Self::Element { Story::container(cx) - .child(Story::title_for::<_, Details>(cx)) + .child(Story::title_for::<_, Details>(cx)) .child(Story::label(cx, "Default")) .child(Details::new("The quick brown fox jumps over the lazy dog")) .child(Story::label(cx, "With meta")) diff --git a/crates/ui2/src/elements/icon.rs b/crates/ui2/src/elements/icon.rs index b47e4c6608..4e4ec2bce7 100644 --- a/crates/ui2/src/elements/icon.rs +++ b/crates/ui2/src/elements/icon.rs @@ -2,7 +2,6 @@ use gpui2::{svg, Hsla}; use strum::EnumIter; use crate::prelude::*; -use crate::theme::old_theme; #[derive(Default, PartialEq, Copy, Clone)] pub enum IconSize { @@ -27,17 +26,17 @@ pub enum IconColor { impl IconColor { pub fn color(self, cx: &WindowContext) -> Hsla { - let theme = old_theme(cx); + let theme = theme(cx); match self { - IconColor::Default => theme.lowest.base.default.foreground, - IconColor::Muted => theme.lowest.variant.default.foreground, - IconColor::Disabled => theme.lowest.base.disabled.foreground, - IconColor::Placeholder => theme.lowest.base.disabled.foreground, - IconColor::Accent => theme.lowest.accent.default.foreground, - IconColor::Error => theme.lowest.negative.default.foreground, - IconColor::Warning => theme.lowest.warning.default.foreground, - IconColor::Success => theme.lowest.positive.default.foreground, - IconColor::Info => theme.lowest.accent.default.foreground, + IconColor::Default => gpui2::red(), + IconColor::Muted => gpui2::red(), + IconColor::Disabled => gpui2::red(), + IconColor::Placeholder => gpui2::red(), + IconColor::Accent => gpui2::red(), + IconColor::Error => gpui2::red(), + IconColor::Warning => gpui2::red(), + IconColor::Success => gpui2::red(), + IconColor::Info => gpui2::red(), } } } @@ -192,17 +191,19 @@ pub use stories::*; #[cfg(feature = "stories")] mod stories { + use gpui2::{Div, Render}; use strum::IntoEnumIterator; use crate::Story; use super::*; - #[derive(Component)] pub struct IconStory; - impl IconStory { - fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { + impl Render for IconStory { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Self::Element { let icons = Icon::iter(); Story::container(cx) diff --git a/crates/ui2/src/elements/input.rs b/crates/ui2/src/elements/input.rs index 79a09e0ba2..e9e92dd0a6 100644 --- a/crates/ui2/src/elements/input.rs +++ b/crates/ui2/src/elements/input.rs @@ -112,15 +112,16 @@ pub use stories::*; #[cfg(feature = "stories")] mod stories { - use crate::Story; - use super::*; + use crate::Story; + use gpui2::{Div, Render}; - #[derive(Component)] pub struct InputStory; - impl InputStory { - fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { + impl Render for InputStory { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Self::Element { Story::container(cx) .child(Story::title_for::<_, Input>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/elements/label.rs b/crates/ui2/src/elements/label.rs index f4014d5922..4d336345fb 100644 --- a/crates/ui2/src/elements/label.rs +++ b/crates/ui2/src/elements/label.rs @@ -2,8 +2,6 @@ use gpui2::{relative, Hsla, WindowContext}; use smallvec::SmallVec; use crate::prelude::*; -use crate::theme::old_theme; - #[derive(Default, PartialEq, Copy, Clone)] pub enum LabelColor { #[default] @@ -21,19 +19,17 @@ pub enum LabelColor { impl LabelColor { pub fn hsla(&self, cx: &WindowContext) -> Hsla { let theme = theme(cx); - // TODO: Remove - let old_theme = old_theme(cx); match self { Self::Default => theme.text, Self::Muted => theme.text_muted, - Self::Created => old_theme.middle.positive.default.foreground, - Self::Modified => old_theme.middle.warning.default.foreground, - Self::Deleted => old_theme.middle.negative.default.foreground, + Self::Created => gpui2::red(), + Self::Modified => gpui2::red(), + Self::Deleted => gpui2::red(), Self::Disabled => theme.text_disabled, - Self::Hidden => old_theme.middle.variant.default.foreground, + Self::Hidden => gpui2::red(), Self::Placeholder => theme.text_placeholder, - Self::Accent => old_theme.middle.accent.default.foreground, + Self::Accent => gpui2::red(), } } } @@ -201,15 +197,16 @@ pub use stories::*; #[cfg(feature = "stories")] mod stories { - use crate::Story; - use super::*; + use crate::Story; + use gpui2::{Div, Render}; - #[derive(Component)] pub struct LabelStory; - impl LabelStory { - fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { + impl Render for LabelStory { + type Element = Div; + + fn render(&mut self, cx: &mut ViewContext) -> Self::Element { Story::container(cx) .child(Story::title_for::<_, Label>(cx)) .child(Story::label(cx, "Default")) diff --git a/crates/ui2/src/lib.rs b/crates/ui2/src/lib.rs index 689e9c5372..c1da5e410d 100644 --- a/crates/ui2/src/lib.rs +++ b/crates/ui2/src/lib.rs @@ -23,7 +23,6 @@ mod elevation; pub mod prelude; pub mod settings; mod static_data; -mod theme; pub use components::*; pub use elements::*; @@ -38,7 +37,6 @@ pub use static_data::*; // AFAICT this is something to do with conflicting names between crates and modules that // interfaces with declaring the `ClassDecl`. pub use crate::settings::*; -pub use crate::theme::*; #[cfg(feature = "stories")] mod story; diff --git a/crates/ui2/src/prelude.rs b/crates/ui2/src/prelude.rs index b8143b6e50..63405fc2cb 100644 --- a/crates/ui2/src/prelude.rs +++ b/crates/ui2/src/prelude.rs @@ -5,7 +5,8 @@ pub use gpui2::{ pub use crate::elevation::*; use crate::settings::user_settings; -pub use crate::{old_theme, theme, ButtonVariant, Theme}; +pub use crate::ButtonVariant; +pub use theme2::theme; use gpui2::{rems, Hsla, Rems}; use strum::EnumIter; diff --git a/crates/ui2/src/static_data.rs b/crates/ui2/src/static_data.rs index 72407b6678..68f1e36b2c 100644 --- a/crates/ui2/src/static_data.rs +++ b/crates/ui2/src/static_data.rs @@ -1,7 +1,7 @@ use std::path::PathBuf; use std::str::FromStr; -use gpui2::{AppContext, WindowContext}; +use gpui2::ViewContext; use rand::Rng; use theme2::Theme; @@ -628,7 +628,7 @@ pub fn example_editor_actions() -> Vec { ] } -pub fn empty_editor_example(cx: &mut WindowContext) -> EditorPane { +pub fn empty_editor_example(cx: &mut ViewContext) -> EditorPane { EditorPane::new( cx, static_tabs_example(), @@ -642,7 +642,7 @@ pub fn empty_buffer_example() -> Buffer { Buffer::new("empty-buffer").set_rows(Some(BufferRows::default())) } -pub fn hello_world_rust_editor_example(cx: &mut WindowContext) -> EditorPane { +pub fn hello_world_rust_editor_example(cx: &mut ViewContext) -> EditorPane { let theme = theme(cx); EditorPane::new( @@ -781,7 +781,7 @@ pub fn hello_world_rust_buffer_rows(theme: &Theme) -> Vec { ] } -pub fn hello_world_rust_editor_with_status_example(cx: &mut AppContext) -> EditorPane { +pub fn hello_world_rust_editor_with_status_example(cx: &mut ViewContext) -> EditorPane { let theme = theme(cx); EditorPane::new( diff --git a/crates/ui2/src/theme.rs b/crates/ui2/src/theme.rs deleted file mode 100644 index cc46ddcb17..0000000000 --- a/crates/ui2/src/theme.rs +++ /dev/null @@ -1,225 +0,0 @@ -use gpui2::{ - AnyElement, AppContext, Bounds, Component, Element, Hsla, LayoutId, Pixels, Result, - ViewContext, WindowContext, -}; -use serde::{de::Visitor, Deserialize, Deserializer}; -use std::collections::HashMap; -use std::fmt; -use std::sync::Arc; - -#[derive(Deserialize, Clone, Default, Debug)] -pub struct Theme { - pub name: String, - pub is_light: bool, - pub lowest: Layer, - pub middle: Layer, - pub highest: Layer, - pub popover_shadow: Shadow, - pub modal_shadow: Shadow, - #[serde(deserialize_with = "deserialize_player_colors")] - pub players: Vec, - #[serde(deserialize_with = "deserialize_syntax_colors")] - pub syntax: HashMap, -} - -#[derive(Deserialize, Clone, Default, Debug)] -pub struct Layer { - pub base: StyleSet, - pub variant: StyleSet, - pub on: StyleSet, - pub accent: StyleSet, - pub positive: StyleSet, - pub warning: StyleSet, - pub negative: StyleSet, -} - -#[derive(Deserialize, Clone, Default, Debug)] -pub struct StyleSet { - #[serde(rename = "default")] - pub default: ContainerColors, - pub hovered: ContainerColors, - pub pressed: ContainerColors, - pub active: ContainerColors, - pub disabled: ContainerColors, - pub inverted: ContainerColors, -} - -#[derive(Deserialize, Clone, Default, Debug)] -pub struct ContainerColors { - pub background: Hsla, - pub foreground: Hsla, - pub border: Hsla, -} - -#[derive(Deserialize, Clone, Default, Debug)] -pub struct PlayerColors { - pub selection: Hsla, - pub cursor: Hsla, -} - -#[derive(Deserialize, Clone, Default, Debug)] -pub struct Shadow { - pub blur: u8, - pub color: Hsla, - pub offset: Vec, -} - -fn deserialize_player_colors<'de, D>(deserializer: D) -> Result, D::Error> -where - D: Deserializer<'de>, -{ - struct PlayerArrayVisitor; - - impl<'de> Visitor<'de> for PlayerArrayVisitor { - type Value = Vec; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("an object with integer keys") - } - - fn visit_map>( - self, - mut map: A, - ) -> Result { - let mut players = Vec::with_capacity(8); - while let Some((key, value)) = map.next_entry::()? { - if key < 8 { - players.push(value); - } else { - return Err(serde::de::Error::invalid_value( - serde::de::Unexpected::Unsigned(key as u64), - &"a key in range 0..7", - )); - } - } - Ok(players) - } - } - - deserializer.deserialize_map(PlayerArrayVisitor) -} - -fn deserialize_syntax_colors<'de, D>(deserializer: D) -> Result, D::Error> -where - D: serde::Deserializer<'de>, -{ - #[derive(Deserialize)] - struct ColorWrapper { - color: Hsla, - } - - struct SyntaxVisitor; - - impl<'de> Visitor<'de> for SyntaxVisitor { - type Value = HashMap; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("a map with keys and objects with a single color field as values") - } - - fn visit_map(self, mut map: M) -> Result, M::Error> - where - M: serde::de::MapAccess<'de>, - { - let mut result = HashMap::new(); - while let Some(key) = map.next_key()? { - let wrapper: ColorWrapper = map.next_value()?; // Deserialize values as Hsla - result.insert(key, wrapper.color); - } - Ok(result) - } - } - deserializer.deserialize_map(SyntaxVisitor) -} - -pub fn themed(theme: Theme, cx: &mut ViewContext, build_child: F) -> Themed -where - V: 'static, - E: Element, - F: FnOnce(&mut ViewContext) -> E, -{ - cx.default_global::().0.push(theme.clone()); - let child = build_child(cx); - cx.default_global::().0.pop(); - Themed { theme, child } -} - -pub struct Themed { - pub(crate) theme: Theme, - pub(crate) child: E, -} - -impl Component for Themed -where - V: 'static, - E: 'static + Element + Send, - E::ElementState: Send, -{ - fn render(self) -> AnyElement { - AnyElement::new(self) - } -} - -#[derive(Default)] -struct ThemeStack(Vec); - -impl + Send> Element for Themed -where - V: 'static, - E::ElementState: Send, -{ - type ElementState = E::ElementState; - - fn id(&self) -> Option { - None - } - - fn initialize( - &mut self, - view_state: &mut V, - element_state: Option, - cx: &mut ViewContext, - ) -> Self::ElementState { - cx.default_global::().0.push(self.theme.clone()); - let element_state = self.child.initialize(view_state, element_state, cx); - cx.default_global::().0.pop(); - element_state - } - - fn layout( - &mut self, - view_state: &mut V, - element_state: &mut Self::ElementState, - cx: &mut ViewContext, - ) -> LayoutId - where - Self: Sized, - { - cx.default_global::().0.push(self.theme.clone()); - let layout_id = self.child.layout(view_state, element_state, cx); - cx.default_global::().0.pop(); - layout_id - } - - fn paint( - &mut self, - bounds: Bounds, - view_state: &mut V, - frame_state: &mut Self::ElementState, - cx: &mut ViewContext, - ) where - Self: Sized, - { - cx.default_global::().0.push(self.theme.clone()); - self.child.paint(bounds, view_state, frame_state, cx); - cx.default_global::().0.pop(); - } -} - -pub fn old_theme(cx: &WindowContext) -> Arc { - Arc::new(cx.global::().clone()) -} - -pub fn theme(cx: &AppContext) -> Arc { - theme2::active_theme(cx).clone() -} diff --git a/crates/workspace2/src/item.rs b/crates/workspace2/src/item.rs index 90d08d6c4a..eddc9200f9 100644 --- a/crates/workspace2/src/item.rs +++ b/crates/workspace2/src/item.rs @@ -17,7 +17,7 @@ use theme2::Theme; // use gpui2::geometry::vector::Vector2F; // use gpui2::AnyWindowHandle; // use gpui2::{ -// fonts::HighlightStyle, AnyElement, AnyViewHandle, AppContext, Handle, Task, View, +// fonts::HighlightStyle, AnyElement, AnyViewHandle, AppContext, Model, Task, View, // ViewContext, View, WeakViewHandle, WindowContext, // }; // use project2::{Project, ProjectEntryId, ProjectPath}; @@ -135,14 +135,14 @@ pub trait Item: EventEmitter + Sized { // } // fn save( // &mut self, - // _project: Handle, + // _project: Model, // _cx: &mut ViewContext, // ) -> Task> { // unimplemented!("save() must be implemented if can_save() returns true") // } // fn save_as( // &mut self, - // _project: Handle, + // _project: Model, // _abs_path: PathBuf, // _cx: &mut ViewContext, // ) -> Task> { @@ -150,7 +150,7 @@ pub trait Item: EventEmitter + Sized { // } // fn reload( // &mut self, - // _project: Handle, + // _project: Model, // _cx: &mut ViewContext, // ) -> Task> { // unimplemented!("reload() must be implemented if can_save() returns true") @@ -197,7 +197,7 @@ pub trait Item: EventEmitter + Sized { // } // fn deserialize( - // _project: Handle, + // _project: Model, // _workspace: WeakViewHandle, // _workspace_id: WorkspaceId, // _item_id: ItemId, @@ -229,8 +229,8 @@ use std::{ }; use gpui2::{ - AnyElement, AnyWindowHandle, AppContext, EventEmitter, Handle, HighlightStyle, Pixels, Point, - SharedString, Task, View, ViewContext, VisualContext, WindowContext, + AnyElement, AnyWindowHandle, AppContext, EventEmitter, HighlightStyle, Model, Pixels, Point, + SharedString, Task, View, ViewContext, WindowContext, }; use project2::{Project, ProjectEntryId, ProjectPath}; use smallvec::SmallVec; @@ -279,14 +279,14 @@ pub trait ItemHandle: 'static + Send { fn is_dirty(&self, cx: &AppContext) -> bool; fn has_conflict(&self, cx: &AppContext) -> bool; fn can_save(&self, cx: &AppContext) -> bool; - fn save(&self, project: Handle, cx: &mut WindowContext) -> Task>; + fn save(&self, project: Model, cx: &mut WindowContext) -> Task>; fn save_as( &self, - project: Handle, + project: Model, abs_path: PathBuf, cx: &mut WindowContext, ) -> Task>; - fn reload(&self, project: Handle, cx: &mut WindowContext) -> Task>; + fn reload(&self, project: Model, cx: &mut WindowContext) -> Task>; // fn act_as_type<'a>(&'a self, type_id: TypeId, cx: &'a AppContext) -> Option<&'a AnyViewHandle>; todo!() fn to_followable_item_handle(&self, cx: &AppContext) -> Option>; fn on_release( @@ -587,20 +587,20 @@ impl ItemHandle for View { self.read(cx).can_save(cx) } - fn save(&self, project: Handle, cx: &mut WindowContext) -> Task> { + fn save(&self, project: Model, cx: &mut WindowContext) -> Task> { self.update(cx, |item, cx| item.save(project, cx)) } fn save_as( &self, - project: Handle, + project: Model, abs_path: PathBuf, cx: &mut WindowContext, ) -> Task> { self.update(cx, |item, cx| item.save_as(project, abs_path, cx)) } - fn reload(&self, project: Handle, cx: &mut WindowContext) -> Task> { + fn reload(&self, project: Model, cx: &mut WindowContext) -> Task> { self.update(cx, |item, cx| item.reload(project, cx)) } @@ -688,8 +688,8 @@ pub trait ProjectItem: Item { type Item: project2::Item; fn for_project_item( - project: Handle, - item: Handle, + project: Model, + item: Model, cx: &mut ViewContext, ) -> Self where @@ -714,7 +714,7 @@ pub trait FollowableItem: Item { ) -> bool; fn apply_update_proto( &mut self, - project: &Handle, + project: &Model, message: proto::update_view::Variant, cx: &mut ViewContext, ) -> Task>; @@ -736,7 +736,7 @@ pub trait FollowableItemHandle: ItemHandle { ) -> bool; fn apply_update_proto( &self, - project: &Handle, + project: &Model, message: proto::update_view::Variant, cx: &mut WindowContext, ) -> Task>; @@ -777,7 +777,7 @@ pub trait FollowableItemHandle: ItemHandle { // fn apply_update_proto( // &self, -// project: &Handle, +// project: &Model, // message: proto::update_view::Variant, // cx: &mut WindowContext, // ) -> Task> { @@ -802,7 +802,7 @@ pub trait FollowableItemHandle: ItemHandle { // use super::{Item, ItemEvent}; // use crate::{ItemId, ItemNavHistory, Pane, Workspace, WorkspaceId}; // use gpui2::{ -// elements::Empty, AnyElement, AppContext, Element, Entity, Handle, Task, View, +// elements::Empty, AnyElement, AppContext, Element, Entity, Model, Task, View, // ViewContext, View, WeakViewHandle, // }; // use project2::{Project, ProjectEntryId, ProjectPath, WorktreeId}; @@ -824,7 +824,7 @@ pub trait FollowableItemHandle: ItemHandle { // pub is_dirty: bool, // pub is_singleton: bool, // pub has_conflict: bool, -// pub project_items: Vec>, +// pub project_items: Vec>, // pub nav_history: Option, // pub tab_descriptions: Option>, // pub tab_detail: Cell>, @@ -869,7 +869,7 @@ pub trait FollowableItemHandle: ItemHandle { // } // impl TestProjectItem { -// pub fn new(id: u64, path: &str, cx: &mut AppContext) -> Handle { +// pub fn new(id: u64, path: &str, cx: &mut AppContext) -> Model { // let entry_id = Some(ProjectEntryId::from_proto(id)); // let project_path = Some(ProjectPath { // worktree_id: WorktreeId::from_usize(0), @@ -881,7 +881,7 @@ pub trait FollowableItemHandle: ItemHandle { // }) // } -// pub fn new_untitled(cx: &mut AppContext) -> Handle { +// pub fn new_untitled(cx: &mut AppContext) -> Model { // cx.add_model(|_| Self { // project_path: None, // entry_id: None, @@ -934,7 +934,7 @@ pub trait FollowableItemHandle: ItemHandle { // self // } -// pub fn with_project_items(mut self, items: &[Handle]) -> Self { +// pub fn with_project_items(mut self, items: &[Model]) -> Self { // self.project_items.clear(); // self.project_items.extend(items.iter().cloned()); // self @@ -1045,7 +1045,7 @@ pub trait FollowableItemHandle: ItemHandle { // fn save( // &mut self, -// _: Handle, +// _: Model, // _: &mut ViewContext, // ) -> Task> { // self.save_count += 1; @@ -1055,7 +1055,7 @@ pub trait FollowableItemHandle: ItemHandle { // fn save_as( // &mut self, -// _: Handle, +// _: Model, // _: std::path::PathBuf, // _: &mut ViewContext, // ) -> Task> { @@ -1066,7 +1066,7 @@ pub trait FollowableItemHandle: ItemHandle { // fn reload( // &mut self, -// _: Handle, +// _: Model, // _: &mut ViewContext, // ) -> Task> { // self.reload_count += 1; @@ -1083,7 +1083,7 @@ pub trait FollowableItemHandle: ItemHandle { // } // fn deserialize( -// _project: Handle, +// _project: Model, // _workspace: WeakViewHandle, // workspace_id: WorkspaceId, // _item_id: ItemId, diff --git a/crates/zed/examples/semantic_index_eval.rs b/crates/zed/examples/semantic_index_eval.rs index e750307800..caf8e5f5c7 100644 --- a/crates/zed/examples/semantic_index_eval.rs +++ b/crates/zed/examples/semantic_index_eval.rs @@ -1,4 +1,4 @@ -use ai::embedding::OpenAIEmbeddings; +use ai::providers::open_ai::OpenAIEmbeddingProvider; use anyhow::{anyhow, Result}; use client::{self, UserStore}; use gpui::{AsyncAppContext, ModelHandle, Task}; @@ -475,7 +475,7 @@ fn main() { let semantic_index = SemanticIndex::new( fs.clone(), db_file_path, - Arc::new(OpenAIEmbeddings::new(http_client, cx.background())), + Arc::new(OpenAIEmbeddingProvider::new(http_client, cx.background())), languages.clone(), cx.clone(), ) diff --git a/crates/zed/src/languages/elixir.rs b/crates/zed/src/languages/elixir.rs index 5c0ff273ae..df438d89ee 100644 --- a/crates/zed/src/languages/elixir.rs +++ b/crates/zed/src/languages/elixir.rs @@ -321,8 +321,8 @@ impl LspAdapter for NextLspAdapter { latest_github_release("elixir-tools/next-ls", false, delegate.http_client()).await?; let version = release.name.clone(); let platform = match consts::ARCH { - "x86_64" => "darwin_arm64", - "aarch64" => "darwin_amd64", + "x86_64" => "darwin_amd64", + "aarch64" => "darwin_arm64", other => bail!("Running on unsupported platform: {other}"), }; let asset_name = format!("next_ls_{}", platform); diff --git a/crates/zed2/Cargo.toml b/crates/zed2/Cargo.toml index 3c6f0c7c64..0a9c8de2c1 100644 --- a/crates/zed2/Cargo.toml +++ b/crates/zed2/Cargo.toml @@ -15,6 +15,7 @@ name = "Zed" path = "src/main.rs" [dependencies] +ai2 = { path = "../ai2"} # audio = { path = "../audio" } # activity_indicator = { path = "../activity_indicator" } # auto_update = { path = "../auto_update" } diff --git a/crates/zed2/src/main.rs b/crates/zed2/src/main.rs index b9968a3ef5..a4270856b8 100644 --- a/crates/zed2/src/main.rs +++ b/crates/zed2/src/main.rs @@ -120,7 +120,7 @@ fn main() { let node_runtime = RealNodeRuntime::new(http.clone()); language2::init(cx); - let user_store = cx.entity(|cx| UserStore::new(client.clone(), http.clone(), cx)); + let user_store = cx.build_model(|cx| UserStore::new(client.clone(), http.clone(), cx)); // let workspace_store = cx.add_model(|cx| WorkspaceStore::new(client.clone(), cx)); cx.set_global(client.clone()); diff --git a/crates/zed2/src/zed2.rs b/crates/zed2/src/zed2.rs index 9782c6dd05..bf4133214f 100644 --- a/crates/zed2/src/zed2.rs +++ b/crates/zed2/src/zed2.rs @@ -5,7 +5,7 @@ mod open_listener; pub use assets::*; use client2::{Client, UserStore}; use collections::HashMap; -use gpui2::{AsyncAppContext, Handle, Point}; +use gpui2::{AsyncAppContext, Model}; pub use only_instance::*; pub use open_listener::*; @@ -52,7 +52,7 @@ pub fn connect_to_cli( pub struct AppState { pub client: Arc, - pub user_store: Handle, + pub user_store: Model, } pub async fn handle_cli_connection( diff --git a/script/zed-2-progress-report.py b/script/zed-2-progress-report.py new file mode 100644 index 0000000000..87f7f7b8f7 --- /dev/null +++ b/script/zed-2-progress-report.py @@ -0,0 +1,27 @@ +import os +from pathlib import Path + +THIS_SCRIPT_PATH: Path = Path(__file__) +CRATES_DIR: Path = THIS_SCRIPT_PATH.parent.parent / "crates" + +zed_1_crate_count: int = 0 +zed_2_crate_count: int = 0 + +for child in os.listdir(CRATES_DIR): + child_path: str = os.path.join(CRATES_DIR, child) + + if not os.path.isdir(child_path): + continue + + if child.endswith("2"): + zed_2_crate_count += 1 + else: + zed_1_crate_count += 1 + +print(f"crates ported: {zed_2_crate_count}") +print(f"crates in total: {zed_1_crate_count}") + +percent_complete: float = (zed_2_crate_count / zed_1_crate_count) * 100 +percent_complete_rounded: float = round(percent_complete, 2) + +print(f"progress: {percent_complete_rounded}%")