diff --git a/Cargo.lock b/Cargo.lock index 7a194db0b6..95fa13ee0c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1169,7 +1169,7 @@ dependencies = [ "futures 0.3.28", "gpui2", "language2", - "live_kit_client", + "live_kit_client2", "log", "media", "postage", @@ -4589,6 +4589,39 @@ dependencies = [ "simplelog", ] +[[package]] +name = "live_kit_client2" +version = "0.1.0" +dependencies = [ + "anyhow", + "async-broadcast", + "async-trait", + "block", + "byteorder", + "bytes 1.5.0", + "cocoa", + "collections", + "core-foundation", + "core-graphics", + "foreign-types", + "futures 0.3.28", + "gpui2", + "hmac 0.12.1", + "jwt", + "live_kit_server", + "log", + "media", + "nanoid", + "objc", + "parking_lot 0.11.2", + "postage", + "serde", + "serde_derive", + "serde_json", + "sha2 0.10.7", + "simplelog", +] + [[package]] name = "live_kit_server" version = "0.1.0" @@ -5035,6 +5068,53 @@ dependencies = [ "workspace", ] +[[package]] +name = "multi_buffer2" +version = "0.1.0" +dependencies = [ + "aho-corasick", + "anyhow", + "client2", + "clock", + "collections", + "convert_case 0.6.0", + "copilot2", + "ctor", + "env_logger 0.9.3", + "futures 0.3.28", + "git", + "gpui2", + "indoc", + "itertools 0.10.5", + "language2", + "lazy_static", + "log", + "lsp2", + "ordered-float 2.10.0", + "parking_lot 0.11.2", + "postage", + "project2", + "pulldown-cmark", + "rand 0.8.5", + "rich_text", + "schemars", + "serde", + "serde_derive", + "settings2", + "smallvec", + "smol", + "snippet", + "sum_tree", + "text", + "theme2", + "tree-sitter", + "tree-sitter-html", + "tree-sitter-rust", + "tree-sitter-typescript", + "unindent", + "util", +] + [[package]] name = "multimap" version = "0.8.3" @@ -8759,6 +8839,7 @@ dependencies = [ "gpui2", "indexmap 1.9.3", "parking_lot 0.11.2", + "refineable", "schemars", "serde", "serde_derive", @@ -8768,21 +8849,6 @@ dependencies = [ "util", ] -[[package]] -name = "theme_converter" -version = "0.1.0" -dependencies = [ - "anyhow", - "clap 4.4.4", - "convert_case 0.6.0", - "gpui2", - "log", - "rust-embed", - "serde", - "simplelog", - "theme2", -] - [[package]] name = "theme_selector" version = "0.1.0" @@ -9600,6 +9666,7 @@ dependencies = [ "itertools 0.11.0", "rand 0.8.5", "serde", + "settings2", "smallvec", "strum", "theme2", @@ -10825,7 +10892,7 @@ dependencies = [ [[package]] name = "zed" -version = "0.111.0" +version = "0.112.0" dependencies = [ "activity_indicator", "ai", diff --git a/Cargo.toml b/Cargo.toml index e8ce7634f4..998ea081a6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -61,6 +61,7 @@ members = [ "crates/menu", "crates/menu2", "crates/multi_buffer", + "crates/multi_buffer2", "crates/node_runtime", "crates/notifications", "crates/outline", @@ -92,7 +93,6 @@ members = [ "crates/text", "crates/theme", "crates/theme2", - "crates/theme_converter", "crates/theme_selector", "crates/ui2", "crates/util", diff --git a/crates/assistant/src/codegen.rs b/crates/assistant/src/codegen.rs index 0466259b24..f62c91fcb7 100644 --- a/crates/assistant/src/codegen.rs +++ b/crates/assistant/src/codegen.rs @@ -118,7 +118,7 @@ impl Codegen { let (mut hunks_tx, mut hunks_rx) = mpsc::channel(1); let diff = cx.background().spawn(async move { - let chunks = strip_markdown_codeblock(response.await?); + let chunks = strip_invalid_spans_from_codeblock(response.await?); futures::pin_mut!(chunks); let mut diff = StreamingDiff::new(selected_text.to_string()); @@ -279,12 +279,13 @@ impl Codegen { } } -fn strip_markdown_codeblock( +fn strip_invalid_spans_from_codeblock( stream: impl Stream>, ) -> impl Stream> { let mut first_line = true; let mut buffer = String::new(); - let mut starts_with_fenced_code_block = false; + let mut starts_with_markdown_codeblock = false; + let mut includes_start_or_end_span = false; stream.filter_map(move |chunk| { let chunk = match chunk { Ok(chunk) => chunk, @@ -292,11 +293,31 @@ fn strip_markdown_codeblock( }; buffer.push_str(&chunk); + if buffer.len() > "<|S|".len() && buffer.starts_with("<|S|") { + includes_start_or_end_span = true; + + buffer = buffer + .strip_prefix("<|S|>") + .or_else(|| buffer.strip_prefix("<|S|")) + .unwrap_or(&buffer) + .to_string(); + } else if buffer.ends_with("|E|>") { + includes_start_or_end_span = true; + } else if buffer.starts_with("<|") + || buffer.starts_with("<|S") + || buffer.starts_with("<|S|") + || buffer.ends_with("|") + || buffer.ends_with("|E") + || buffer.ends_with("|E|") + { + return future::ready(None); + } + if first_line { if buffer == "" || buffer == "`" || buffer == "``" { return future::ready(None); } else if buffer.starts_with("```") { - starts_with_fenced_code_block = true; + starts_with_markdown_codeblock = true; if let Some(newline_ix) = buffer.find('\n') { buffer.replace_range(..newline_ix + 1, ""); first_line = false; @@ -306,16 +327,26 @@ fn strip_markdown_codeblock( } } - let text = if starts_with_fenced_code_block { - buffer + let mut text = buffer.to_string(); + if starts_with_markdown_codeblock { + text = text .strip_suffix("\n```\n") - .or_else(|| buffer.strip_suffix("\n```")) - .or_else(|| buffer.strip_suffix("\n``")) - .or_else(|| buffer.strip_suffix("\n`")) - .or_else(|| buffer.strip_suffix('\n')) - .unwrap_or(&buffer) - } else { - &buffer + .or_else(|| text.strip_suffix("\n```")) + .or_else(|| text.strip_suffix("\n``")) + .or_else(|| text.strip_suffix("\n`")) + .or_else(|| text.strip_suffix('\n')) + .unwrap_or(&text) + .to_string(); + } + + if includes_start_or_end_span { + text = text + .strip_suffix("|E|>") + .or_else(|| text.strip_suffix("E|>")) + .or_else(|| text.strip_prefix("|>")) + .or_else(|| text.strip_prefix(">")) + .unwrap_or(&text) + .to_string(); }; if text.contains('\n') { @@ -328,6 +359,7 @@ fn strip_markdown_codeblock( } else { Some(Ok(buffer.clone())) }; + buffer = remainder; future::ready(result) }) @@ -558,50 +590,82 @@ mod tests { } #[gpui::test] - async fn test_strip_markdown_codeblock() { + async fn test_strip_invalid_spans_from_codeblock() { assert_eq!( - strip_markdown_codeblock(chunks("Lorem ipsum dolor", 2)) + strip_invalid_spans_from_codeblock(chunks("Lorem ipsum dolor", 2)) .map(|chunk| chunk.unwrap()) .collect::() .await, "Lorem ipsum dolor" ); assert_eq!( - strip_markdown_codeblock(chunks("```\nLorem ipsum dolor", 2)) + strip_invalid_spans_from_codeblock(chunks("```\nLorem ipsum dolor", 2)) .map(|chunk| chunk.unwrap()) .collect::() .await, "Lorem ipsum dolor" ); assert_eq!( - strip_markdown_codeblock(chunks("```\nLorem ipsum dolor\n```", 2)) + strip_invalid_spans_from_codeblock(chunks("```\nLorem ipsum dolor\n```", 2)) .map(|chunk| chunk.unwrap()) .collect::() .await, "Lorem ipsum dolor" ); assert_eq!( - strip_markdown_codeblock(chunks("```\nLorem ipsum dolor\n```\n", 2)) + strip_invalid_spans_from_codeblock(chunks("```\nLorem ipsum dolor\n```\n", 2)) .map(|chunk| chunk.unwrap()) .collect::() .await, "Lorem ipsum dolor" ); assert_eq!( - strip_markdown_codeblock(chunks("```html\n```js\nLorem ipsum dolor\n```\n```", 2)) - .map(|chunk| chunk.unwrap()) - .collect::() - .await, + strip_invalid_spans_from_codeblock(chunks( + "```html\n```js\nLorem ipsum dolor\n```\n```", + 2 + )) + .map(|chunk| chunk.unwrap()) + .collect::() + .await, "```js\nLorem ipsum dolor\n```" ); assert_eq!( - strip_markdown_codeblock(chunks("``\nLorem ipsum dolor\n```", 2)) + strip_invalid_spans_from_codeblock(chunks("``\nLorem ipsum dolor\n```", 2)) .map(|chunk| chunk.unwrap()) .collect::() .await, "``\nLorem ipsum dolor\n```" ); + assert_eq!( + strip_invalid_spans_from_codeblock(chunks("<|S|Lorem ipsum|E|>", 2)) + .map(|chunk| chunk.unwrap()) + .collect::() + .await, + "Lorem ipsum" + ); + assert_eq!( + strip_invalid_spans_from_codeblock(chunks("<|S|>Lorem ipsum", 2)) + .map(|chunk| chunk.unwrap()) + .collect::() + .await, + "Lorem ipsum" + ); + + assert_eq!( + strip_invalid_spans_from_codeblock(chunks("```\n<|S|>Lorem ipsum\n```", 2)) + .map(|chunk| chunk.unwrap()) + .collect::() + .await, + "Lorem ipsum" + ); + assert_eq!( + strip_invalid_spans_from_codeblock(chunks("```\n<|S|Lorem ipsum|E|>\n```", 2)) + .map(|chunk| chunk.unwrap()) + .collect::() + .await, + "Lorem ipsum" + ); fn chunks(text: &str, size: usize) -> impl Stream> { stream::iter( text.chars() diff --git a/crates/assistant/src/prompts.rs b/crates/assistant/src/prompts.rs index 25af023c40..b678c6fe3b 100644 --- a/crates/assistant/src/prompts.rs +++ b/crates/assistant/src/prompts.rs @@ -80,12 +80,12 @@ fn summarize(buffer: &BufferSnapshot, selected_range: Range) -> S if !flushed_selection { // The collapsed node ends after the selection starts, so we'll flush the selection first. summary.extend(buffer.text_for_range(offset..selected_range.start)); - summary.push_str("<|START|"); + summary.push_str("<|S|"); if selected_range.end == selected_range.start { summary.push_str(">"); } else { summary.extend(buffer.text_for_range(selected_range.clone())); - summary.push_str("|END|>"); + summary.push_str("|E|>"); } offset = selected_range.end; flushed_selection = true; @@ -107,12 +107,12 @@ fn summarize(buffer: &BufferSnapshot, selected_range: Range) -> S // Flush selection if we haven't already done so. if !flushed_selection && offset <= selected_range.start { summary.extend(buffer.text_for_range(offset..selected_range.start)); - summary.push_str("<|START|"); + summary.push_str("<|S|"); if selected_range.end == selected_range.start { summary.push_str(">"); } else { summary.extend(buffer.text_for_range(selected_range.clone())); - summary.push_str("|END|>"); + summary.push_str("|E|>"); } offset = selected_range.end; } @@ -260,7 +260,7 @@ pub(crate) mod tests { summarize(&snapshot, Point::new(1, 4)..Point::new(1, 4)), indoc! {" struct X { - <|START|>a: usize, + <|S|>a: usize, b: usize, } @@ -286,7 +286,7 @@ pub(crate) mod tests { impl X { fn new() -> Self { - let <|START|a |END|>= 1; + let <|S|a |E|>= 1; let b = 2; Self { a, b } } @@ -307,7 +307,7 @@ pub(crate) mod tests { } impl X { - <|START|> + <|S|> fn new() -> Self {} pub fn a(&self, param: bool) -> usize {} @@ -333,7 +333,7 @@ pub(crate) mod tests { pub fn b(&self) -> usize {} } - <|START|>"} + <|S|>"} ); // Ensure nested functions get collapsed properly. @@ -369,7 +369,7 @@ pub(crate) mod tests { assert_eq!( summarize(&snapshot, Point::new(0, 0)..Point::new(0, 0)), indoc! {" - <|START|>struct X { + <|S|>struct X { a: usize, b: usize, } diff --git a/crates/call2/Cargo.toml b/crates/call2/Cargo.toml index f0e47832ed..e918ada3e8 100644 --- a/crates/call2/Cargo.toml +++ b/crates/call2/Cargo.toml @@ -13,7 +13,7 @@ test-support = [ "client2/test-support", "collections/test-support", "gpui2/test-support", - "live_kit_client/test-support", + "live_kit_client2/test-support", "project2/test-support", "util/test-support" ] @@ -24,7 +24,7 @@ client2 = { path = "../client2" } collections = { path = "../collections" } gpui2 = { path = "../gpui2" } log.workspace = true -live_kit_client = { path = "../live_kit_client" } +live_kit_client2 = { path = "../live_kit_client2" } fs2 = { path = "../fs2" } language2 = { path = "../language2" } media = { path = "../media" } @@ -47,6 +47,6 @@ fs2 = { path = "../fs2", features = ["test-support"] } language2 = { path = "../language2", features = ["test-support"] } collections = { path = "../collections", features = ["test-support"] } gpui2 = { path = "../gpui2", features = ["test-support"] } -live_kit_client = { path = "../live_kit_client", features = ["test-support"] } +live_kit_client2 = { path = "../live_kit_client2", features = ["test-support"] } project2 = { path = "../project2", features = ["test-support"] } util = { path = "../util", features = ["test-support"] } diff --git a/crates/call2/src/participant.rs b/crates/call2/src/participant.rs index 7f3e91dbba..9fe212e776 100644 --- a/crates/call2/src/participant.rs +++ b/crates/call2/src/participant.rs @@ -1,10 +1,12 @@ use anyhow::{anyhow, Result}; use client2::ParticipantIndex; use client2::{proto, User}; +use collections::HashMap; use gpui2::WeakModel; -pub use live_kit_client::Frame; +pub use live_kit_client2::Frame; +use live_kit_client2::{RemoteAudioTrack, RemoteVideoTrack}; use project2::Project; -use std::{fmt, sync::Arc}; +use std::sync::Arc; #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum ParticipantLocation { @@ -45,27 +47,6 @@ pub struct RemoteParticipant { pub participant_index: ParticipantIndex, pub muted: bool, pub speaking: bool, - // pub video_tracks: HashMap>, - // pub audio_tracks: HashMap>, -} - -#[derive(Clone)] -pub struct RemoteVideoTrack { - pub(crate) live_kit_track: Arc, -} - -unsafe impl Send for RemoteVideoTrack {} -// todo!("remove this sync because it's not legit") -unsafe impl Sync for RemoteVideoTrack {} - -impl fmt::Debug for RemoteVideoTrack { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("RemoteVideoTrack").finish() - } -} - -impl RemoteVideoTrack { - pub fn frames(&self) -> async_broadcast::Receiver { - self.live_kit_track.frames() - } + pub video_tracks: HashMap>, + pub audio_tracks: HashMap>, } diff --git a/crates/call2/src/room.rs b/crates/call2/src/room.rs index b7bac52a8b..cf98db015b 100644 --- a/crates/call2/src/room.rs +++ b/crates/call2/src/room.rs @@ -1,9 +1,6 @@ -#![allow(dead_code, unused)] -// todo!() - use crate::{ call_settings::CallSettings, - participant::{LocalParticipant, ParticipantLocation, RemoteParticipant, RemoteVideoTrack}, + participant::{LocalParticipant, ParticipantLocation, RemoteParticipant}, IncomingCall, }; use anyhow::{anyhow, Result}; @@ -19,12 +16,15 @@ use gpui2::{ AppContext, AsyncAppContext, Context, EventEmitter, Model, ModelContext, Task, WeakModel, }; use language2::LanguageRegistry; -use live_kit_client::{LocalTrackPublication, RemoteAudioTrackUpdate, RemoteVideoTrackUpdate}; +use live_kit_client2::{ + LocalAudioTrack, LocalTrackPublication, LocalVideoTrack, RemoteAudioTrackUpdate, + RemoteVideoTrackUpdate, +}; use postage::{sink::Sink, stream::Stream, watch}; use project2::Project; use settings2::Settings; -use std::{future::Future, sync::Arc, time::Duration}; -use util::{ResultExt, TryFutureExt}; +use std::{future::Future, mem, sync::Arc, time::Duration}; +use util::{post_inc, ResultExt, TryFutureExt}; pub const RECONNECT_TIMEOUT: Duration = Duration::from_secs(30); @@ -59,7 +59,7 @@ pub enum Event { pub struct Room { id: u64, channel_id: Option, - // live_kit: Option, + live_kit: Option, status: RoomStatus, shared_projects: HashSet>, joined_projects: HashSet>, @@ -95,15 +95,14 @@ impl Room { #[cfg(any(test, feature = "test-support"))] pub fn is_connected(&self) -> bool { - false - // if let Some(live_kit) = self.live_kit.as_ref() { - // matches!( - // *live_kit.room.status().borrow(), - // live_kit_client::ConnectionState::Connected { .. } - // ) - // } else { - // false - // } + if let Some(live_kit) = self.live_kit.as_ref() { + matches!( + *live_kit.room.status().borrow(), + live_kit_client2::ConnectionState::Connected { .. } + ) + } else { + false + } } fn new( @@ -114,125 +113,130 @@ impl Room { user_store: Model, cx: &mut ModelContext, ) -> Self { - todo!() - // let _live_kit_room = if let Some(connection_info) = live_kit_connection_info { - // let room = live_kit_client::Room::new(); - // let mut status = room.status(); - // // Consume the initial status of the room. - // let _ = status.try_recv(); - // let _maintain_room = cx.spawn(|this, mut cx| async move { - // while let Some(status) = status.next().await { - // let this = if let Some(this) = this.upgrade() { - // this - // } else { - // break; - // }; + let live_kit_room = if let Some(connection_info) = live_kit_connection_info { + let room = live_kit_client2::Room::new(); + let mut status = room.status(); + // Consume the initial status of the room. + let _ = status.try_recv(); + let _maintain_room = cx.spawn(|this, mut cx| async move { + while let Some(status) = status.next().await { + let this = if let Some(this) = this.upgrade() { + this + } else { + break; + }; - // if status == live_kit_client::ConnectionState::Disconnected { - // this.update(&mut cx, |this, cx| this.leave(cx).log_err()) - // .ok(); - // break; - // } - // } - // }); + if status == live_kit_client2::ConnectionState::Disconnected { + this.update(&mut cx, |this, cx| this.leave(cx).log_err()) + .ok(); + break; + } + } + }); - // let mut track_video_changes = room.remote_video_track_updates(); - // let _maintain_video_tracks = cx.spawn(|this, mut cx| async move { - // while let Some(track_change) = track_video_changes.next().await { - // let this = if let Some(this) = this.upgrade() { - // this - // } else { - // break; - // }; + let _maintain_video_tracks = cx.spawn_on_main({ + let room = room.clone(); + move |this, mut cx| async move { + let mut track_video_changes = room.remote_video_track_updates(); + while let Some(track_change) = track_video_changes.next().await { + let this = if let Some(this) = this.upgrade() { + this + } else { + break; + }; - // this.update(&mut cx, |this, cx| { - // this.remote_video_track_updated(track_change, cx).log_err() - // }) - // .ok(); - // } - // }); + this.update(&mut cx, |this, cx| { + this.remote_video_track_updated(track_change, cx).log_err() + }) + .ok(); + } + } + }); - // let mut track_audio_changes = room.remote_audio_track_updates(); - // let _maintain_audio_tracks = cx.spawn(|this, mut cx| async move { - // while let Some(track_change) = track_audio_changes.next().await { - // let this = if let Some(this) = this.upgrade() { - // this - // } else { - // break; - // }; + let _maintain_audio_tracks = cx.spawn_on_main({ + let room = room.clone(); + |this, mut cx| async move { + let mut track_audio_changes = room.remote_audio_track_updates(); + while let Some(track_change) = track_audio_changes.next().await { + let this = if let Some(this) = this.upgrade() { + this + } else { + break; + }; - // this.update(&mut cx, |this, cx| { - // this.remote_audio_track_updated(track_change, cx).log_err() - // }) - // .ok(); - // } - // }); + this.update(&mut cx, |this, cx| { + this.remote_audio_track_updated(track_change, cx).log_err() + }) + .ok(); + } + } + }); - // let connect = room.connect(&connection_info.server_url, &connection_info.token); - // cx.spawn(|this, mut cx| async move { - // connect.await?; + let connect = room.connect(&connection_info.server_url, &connection_info.token); + cx.spawn(|this, mut cx| async move { + connect.await?; - // if !cx.update(|cx| Self::mute_on_join(cx))? { - // this.update(&mut cx, |this, cx| this.share_microphone(cx))? - // .await?; - // } + if !cx.update(|cx| Self::mute_on_join(cx))? { + this.update(&mut cx, |this, cx| this.share_microphone(cx))? + .await?; + } - // anyhow::Ok(()) - // }) - // .detach_and_log_err(cx); + anyhow::Ok(()) + }) + .detach_and_log_err(cx); - // Some(LiveKitRoom { - // room, - // screen_track: LocalTrack::None, - // microphone_track: LocalTrack::None, - // next_publish_id: 0, - // muted_by_user: false, - // deafened: false, - // speaking: false, - // _maintain_room, - // _maintain_tracks: [_maintain_video_tracks, _maintain_audio_tracks], - // }) - // } else { - // None - // }; + Some(LiveKitRoom { + room, + screen_track: LocalTrack::None, + microphone_track: LocalTrack::None, + next_publish_id: 0, + muted_by_user: false, + deafened: false, + speaking: false, + _maintain_room, + _maintain_tracks: [_maintain_video_tracks, _maintain_audio_tracks], + }) + } else { + None + }; - // let maintain_connection = cx.spawn({ - // let client = client.clone(); - // move |this, cx| Self::maintain_connection(this, client.clone(), cx).log_err() - // }); + let maintain_connection = cx.spawn({ + let client = client.clone(); + move |this, cx| Self::maintain_connection(this, client.clone(), cx).log_err() + }); - // Audio::play_sound(Sound::Joined, cx); + Audio::play_sound(Sound::Joined, cx); - // let (room_update_completed_tx, room_update_completed_rx) = watch::channel(); + let (room_update_completed_tx, room_update_completed_rx) = watch::channel(); - // Self { - // id, - // channel_id, - // // live_kit: live_kit_room, - // status: RoomStatus::Online, - // shared_projects: Default::default(), - // joined_projects: Default::default(), - // participant_user_ids: Default::default(), - // local_participant: Default::default(), - // remote_participants: Default::default(), - // pending_participants: Default::default(), - // pending_call_count: 0, - // client_subscriptions: vec![ - // client.add_message_handler(cx.weak_handle(), Self::handle_room_updated) - // ], - // _subscriptions: vec![ - // cx.on_release(Self::released), - // cx.on_app_quit(Self::app_will_quit), - // ], - // leave_when_empty: false, - // pending_room_update: None, - // client, - // user_store, - // follows_by_leader_id_project_id: Default::default(), - // maintain_connection: Some(maintain_connection), - // room_update_completed_tx, - // room_update_completed_rx, - // } + Self { + id, + channel_id, + live_kit: live_kit_room, + status: RoomStatus::Online, + shared_projects: Default::default(), + joined_projects: Default::default(), + participant_user_ids: Default::default(), + local_participant: Default::default(), + remote_participants: Default::default(), + pending_participants: Default::default(), + pending_call_count: 0, + client_subscriptions: vec![ + client.add_message_handler(cx.weak_model(), Self::handle_room_updated) + ], + _subscriptions: vec![ + cx.on_release(Self::released), + cx.on_app_quit(Self::app_will_quit), + ], + leave_when_empty: false, + pending_room_update: None, + client, + user_store, + follows_by_leader_id_project_id: Default::default(), + maintain_connection: Some(maintain_connection), + room_update_completed_tx, + room_update_completed_rx, + } } pub(crate) fn create( @@ -418,7 +422,7 @@ impl Room { self.pending_participants.clear(); self.participant_user_ids.clear(); self.client_subscriptions.clear(); - // self.live_kit.take(); + self.live_kit.take(); self.pending_room_update.take(); self.maintain_connection.take(); } @@ -794,43 +798,43 @@ impl Room { location, muted: true, speaking: false, - // video_tracks: Default::default(), - // audio_tracks: Default::default(), + video_tracks: Default::default(), + audio_tracks: Default::default(), }, ); Audio::play_sound(Sound::Joined, cx); - // if let Some(live_kit) = this.live_kit.as_ref() { - // let video_tracks = - // live_kit.room.remote_video_tracks(&user.id.to_string()); - // let audio_tracks = - // live_kit.room.remote_audio_tracks(&user.id.to_string()); - // let publications = live_kit - // .room - // .remote_audio_track_publications(&user.id.to_string()); + if let Some(live_kit) = this.live_kit.as_ref() { + let video_tracks = + live_kit.room.remote_video_tracks(&user.id.to_string()); + let audio_tracks = + live_kit.room.remote_audio_tracks(&user.id.to_string()); + let publications = live_kit + .room + .remote_audio_track_publications(&user.id.to_string()); - // for track in video_tracks { - // this.remote_video_track_updated( - // RemoteVideoTrackUpdate::Subscribed(track), - // cx, - // ) - // .log_err(); - // } + for track in video_tracks { + this.remote_video_track_updated( + RemoteVideoTrackUpdate::Subscribed(track), + cx, + ) + .log_err(); + } - // for (track, publication) in - // audio_tracks.iter().zip(publications.iter()) - // { - // this.remote_audio_track_updated( - // RemoteAudioTrackUpdate::Subscribed( - // track.clone(), - // publication.clone(), - // ), - // cx, - // ) - // .log_err(); - // } - // } + for (track, publication) in + audio_tracks.iter().zip(publications.iter()) + { + this.remote_audio_track_updated( + RemoteAudioTrackUpdate::Subscribed( + track.clone(), + publication.clone(), + ), + cx, + ) + .log_err(); + } + } } } @@ -918,7 +922,6 @@ impl Room { change: RemoteVideoTrackUpdate, cx: &mut ModelContext, ) -> Result<()> { - todo!(); match change { RemoteVideoTrackUpdate::Subscribed(track) => { let user_id = track.publisher_id().parse()?; @@ -927,12 +930,7 @@ impl Room { .remote_participants .get_mut(&user_id) .ok_or_else(|| anyhow!("subscribed to track by unknown participant"))?; - // participant.video_tracks.insert( - // track_id.clone(), - // Arc::new(RemoteVideoTrack { - // live_kit_track: track, - // }), - // ); + participant.video_tracks.insert(track_id.clone(), track); cx.emit(Event::RemoteVideoTracksChanged { participant_id: participant.peer_id, }); @@ -946,7 +944,7 @@ impl Room { .remote_participants .get_mut(&user_id) .ok_or_else(|| anyhow!("unsubscribed from track by unknown participant"))?; - // participant.video_tracks.remove(&track_id); + participant.video_tracks.remove(&track_id); cx.emit(Event::RemoteVideoTracksChanged { participant_id: participant.peer_id, }); @@ -976,65 +974,61 @@ impl Room { participant.speaking = false; } } - // todo!() - // if let Some(id) = self.client.user_id() { - // if let Some(room) = &mut self.live_kit { - // if let Ok(_) = speaker_ids.binary_search(&id) { - // room.speaking = true; - // } else { - // room.speaking = false; - // } - // } - // } + if let Some(id) = self.client.user_id() { + if let Some(room) = &mut self.live_kit { + if let Ok(_) = speaker_ids.binary_search(&id) { + room.speaking = true; + } else { + room.speaking = false; + } + } + } cx.notify(); } RemoteAudioTrackUpdate::MuteChanged { track_id, muted } => { - // todo!() - // let mut found = false; - // for participant in &mut self.remote_participants.values_mut() { - // for track in participant.audio_tracks.values() { - // if track.sid() == track_id { - // found = true; - // break; - // } - // } - // if found { - // participant.muted = muted; - // break; - // } - // } + let mut found = false; + for participant in &mut self.remote_participants.values_mut() { + for track in participant.audio_tracks.values() { + if track.sid() == track_id { + found = true; + break; + } + } + if found { + participant.muted = muted; + break; + } + } cx.notify(); } RemoteAudioTrackUpdate::Subscribed(track, publication) => { - // todo!() - // let user_id = track.publisher_id().parse()?; - // let track_id = track.sid().to_string(); - // let participant = self - // .remote_participants - // .get_mut(&user_id) - // .ok_or_else(|| anyhow!("subscribed to track by unknown participant"))?; - // // participant.audio_tracks.insert(track_id.clone(), track); - // participant.muted = publication.is_muted(); + let user_id = track.publisher_id().parse()?; + let track_id = track.sid().to_string(); + let participant = self + .remote_participants + .get_mut(&user_id) + .ok_or_else(|| anyhow!("subscribed to track by unknown participant"))?; + participant.audio_tracks.insert(track_id.clone(), track); + participant.muted = publication.is_muted(); - // cx.emit(Event::RemoteAudioTracksChanged { - // participant_id: participant.peer_id, - // }); + cx.emit(Event::RemoteAudioTracksChanged { + participant_id: participant.peer_id, + }); } RemoteAudioTrackUpdate::Unsubscribed { publisher_id, track_id, } => { - // todo!() - // let user_id = publisher_id.parse()?; - // let participant = self - // .remote_participants - // .get_mut(&user_id) - // .ok_or_else(|| anyhow!("unsubscribed from track by unknown participant"))?; - // participant.audio_tracks.remove(&track_id); - // cx.emit(Event::RemoteAudioTracksChanged { - // participant_id: participant.peer_id, - // }); + let user_id = publisher_id.parse()?; + let participant = self + .remote_participants + .get_mut(&user_id) + .ok_or_else(|| anyhow!("unsubscribed from track by unknown participant"))?; + participant.audio_tracks.remove(&track_id); + cx.emit(Event::RemoteAudioTracksChanged { + participant_id: participant.peer_id, + }); } } @@ -1215,278 +1209,269 @@ impl Room { } pub fn is_screen_sharing(&self) -> bool { - todo!() - // self.live_kit.as_ref().map_or(false, |live_kit| { - // !matches!(live_kit.screen_track, LocalTrack::None) - // }) + self.live_kit.as_ref().map_or(false, |live_kit| { + !matches!(live_kit.screen_track, LocalTrack::None) + }) } pub fn is_sharing_mic(&self) -> bool { - todo!() - // self.live_kit.as_ref().map_or(false, |live_kit| { - // !matches!(live_kit.microphone_track, LocalTrack::None) - // }) + self.live_kit.as_ref().map_or(false, |live_kit| { + !matches!(live_kit.microphone_track, LocalTrack::None) + }) } pub fn is_muted(&self, cx: &AppContext) -> bool { - todo!() - // self.live_kit - // .as_ref() - // .and_then(|live_kit| match &live_kit.microphone_track { - // LocalTrack::None => Some(Self::mute_on_join(cx)), - // LocalTrack::Pending { muted, .. } => Some(*muted), - // LocalTrack::Published { muted, .. } => Some(*muted), - // }) - // .unwrap_or(false) + self.live_kit + .as_ref() + .and_then(|live_kit| match &live_kit.microphone_track { + LocalTrack::None => Some(Self::mute_on_join(cx)), + LocalTrack::Pending { muted, .. } => Some(*muted), + LocalTrack::Published { muted, .. } => Some(*muted), + }) + .unwrap_or(false) } pub fn is_speaking(&self) -> bool { - todo!() - // self.live_kit - // .as_ref() - // .map_or(false, |live_kit| live_kit.speaking) + self.live_kit + .as_ref() + .map_or(false, |live_kit| live_kit.speaking) } pub fn is_deafened(&self) -> Option { - // self.live_kit.as_ref().map(|live_kit| live_kit.deafened) - todo!() + self.live_kit.as_ref().map(|live_kit| live_kit.deafened) } #[track_caller] pub fn share_microphone(&mut self, cx: &mut ModelContext) -> Task> { - todo!() - // if self.status.is_offline() { - // return Task::ready(Err(anyhow!("room is offline"))); - // } else if self.is_sharing_mic() { - // return Task::ready(Err(anyhow!("microphone was already shared"))); - // } + if self.status.is_offline() { + return Task::ready(Err(anyhow!("room is offline"))); + } else if self.is_sharing_mic() { + return Task::ready(Err(anyhow!("microphone was already shared"))); + } - // let publish_id = if let Some(live_kit) = self.live_kit.as_mut() { - // let publish_id = post_inc(&mut live_kit.next_publish_id); - // live_kit.microphone_track = LocalTrack::Pending { - // publish_id, - // muted: false, - // }; - // cx.notify(); - // publish_id - // } else { - // return Task::ready(Err(anyhow!("live-kit was not initialized"))); - // }; + let publish_id = if let Some(live_kit) = self.live_kit.as_mut() { + let publish_id = post_inc(&mut live_kit.next_publish_id); + live_kit.microphone_track = LocalTrack::Pending { + publish_id, + muted: false, + }; + cx.notify(); + publish_id + } else { + return Task::ready(Err(anyhow!("live-kit was not initialized"))); + }; - // cx.spawn(move |this, mut cx| async move { - // let publish_track = async { - // let track = LocalAudioTrack::create(); - // this.upgrade() - // .ok_or_else(|| anyhow!("room was dropped"))? - // .update(&mut cx, |this, _| { - // this.live_kit - // .as_ref() - // .map(|live_kit| live_kit.room.publish_audio_track(track)) - // })? - // .ok_or_else(|| anyhow!("live-kit was not initialized"))? - // .await - // }; + cx.spawn(move |this, mut cx| async move { + let publish_track = async { + let track = LocalAudioTrack::create(); + this.upgrade() + .ok_or_else(|| anyhow!("room was dropped"))? + .update(&mut cx, |this, _| { + this.live_kit + .as_ref() + .map(|live_kit| live_kit.room.publish_audio_track(track)) + })? + .ok_or_else(|| anyhow!("live-kit was not initialized"))? + .await + }; - // let publication = publish_track.await; - // this.upgrade() - // .ok_or_else(|| anyhow!("room was dropped"))? - // .update(&mut cx, |this, cx| { - // let live_kit = this - // .live_kit - // .as_mut() - // .ok_or_else(|| anyhow!("live-kit was not initialized"))?; + let publication = publish_track.await; + this.upgrade() + .ok_or_else(|| anyhow!("room was dropped"))? + .update(&mut cx, |this, cx| { + let live_kit = this + .live_kit + .as_mut() + .ok_or_else(|| anyhow!("live-kit was not initialized"))?; - // let (canceled, muted) = if let LocalTrack::Pending { - // publish_id: cur_publish_id, - // muted, - // } = &live_kit.microphone_track - // { - // (*cur_publish_id != publish_id, *muted) - // } else { - // (true, false) - // }; + let (canceled, muted) = if let LocalTrack::Pending { + publish_id: cur_publish_id, + muted, + } = &live_kit.microphone_track + { + (*cur_publish_id != publish_id, *muted) + } else { + (true, false) + }; - // match publication { - // Ok(publication) => { - // if canceled { - // live_kit.room.unpublish_track(publication); - // } else { - // if muted { - // cx.executor().spawn(publication.set_mute(muted)).detach(); - // } - // live_kit.microphone_track = LocalTrack::Published { - // track_publication: publication, - // muted, - // }; - // cx.notify(); - // } - // Ok(()) - // } - // Err(error) => { - // if canceled { - // Ok(()) - // } else { - // live_kit.microphone_track = LocalTrack::None; - // cx.notify(); - // Err(error) - // } - // } - // } - // })? - // }) + match publication { + Ok(publication) => { + if canceled { + live_kit.room.unpublish_track(publication); + } else { + if muted { + cx.executor().spawn(publication.set_mute(muted)).detach(); + } + live_kit.microphone_track = LocalTrack::Published { + track_publication: publication, + muted, + }; + cx.notify(); + } + Ok(()) + } + Err(error) => { + if canceled { + Ok(()) + } else { + live_kit.microphone_track = LocalTrack::None; + cx.notify(); + Err(error) + } + } + } + })? + }) } pub fn share_screen(&mut self, cx: &mut ModelContext) -> Task> { - todo!() - // if self.status.is_offline() { - // return Task::ready(Err(anyhow!("room is offline"))); - // } else if self.is_screen_sharing() { - // return Task::ready(Err(anyhow!("screen was already shared"))); - // } + if self.status.is_offline() { + return Task::ready(Err(anyhow!("room is offline"))); + } else if self.is_screen_sharing() { + return Task::ready(Err(anyhow!("screen was already shared"))); + } - // let (displays, publish_id) = if let Some(live_kit) = self.live_kit.as_mut() { - // let publish_id = post_inc(&mut live_kit.next_publish_id); - // live_kit.screen_track = LocalTrack::Pending { - // publish_id, - // muted: false, - // }; - // cx.notify(); - // (live_kit.room.display_sources(), publish_id) - // } else { - // return Task::ready(Err(anyhow!("live-kit was not initialized"))); - // }; + let (displays, publish_id) = if let Some(live_kit) = self.live_kit.as_mut() { + let publish_id = post_inc(&mut live_kit.next_publish_id); + live_kit.screen_track = LocalTrack::Pending { + publish_id, + muted: false, + }; + cx.notify(); + (live_kit.room.display_sources(), publish_id) + } else { + return Task::ready(Err(anyhow!("live-kit was not initialized"))); + }; - // cx.spawn(move |this, mut cx| async move { - // let publish_track = async { - // let displays = displays.await?; - // let display = displays - // .first() - // .ok_or_else(|| anyhow!("no display found"))?; - // let track = LocalVideoTrack::screen_share_for_display(&display); - // this.upgrade() - // .ok_or_else(|| anyhow!("room was dropped"))? - // .update(&mut cx, |this, _| { - // this.live_kit - // .as_ref() - // .map(|live_kit| live_kit.room.publish_video_track(track)) - // })? - // .ok_or_else(|| anyhow!("live-kit was not initialized"))? - // .await - // }; + cx.spawn_on_main(move |this, mut cx| async move { + let publish_track = async { + let displays = displays.await?; + let display = displays + .first() + .ok_or_else(|| anyhow!("no display found"))?; + let track = LocalVideoTrack::screen_share_for_display(&display); + this.upgrade() + .ok_or_else(|| anyhow!("room was dropped"))? + .update(&mut cx, |this, _| { + this.live_kit + .as_ref() + .map(|live_kit| live_kit.room.publish_video_track(track)) + })? + .ok_or_else(|| anyhow!("live-kit was not initialized"))? + .await + }; - // let publication = publish_track.await; - // this.upgrade() - // .ok_or_else(|| anyhow!("room was dropped"))? - // .update(&mut cx, |this, cx| { - // let live_kit = this - // .live_kit - // .as_mut() - // .ok_or_else(|| anyhow!("live-kit was not initialized"))?; + let publication = publish_track.await; + this.upgrade() + .ok_or_else(|| anyhow!("room was dropped"))? + .update(&mut cx, |this, cx| { + let live_kit = this + .live_kit + .as_mut() + .ok_or_else(|| anyhow!("live-kit was not initialized"))?; - // let (canceled, muted) = if let LocalTrack::Pending { - // publish_id: cur_publish_id, - // muted, - // } = &live_kit.screen_track - // { - // (*cur_publish_id != publish_id, *muted) - // } else { - // (true, false) - // }; + let (canceled, muted) = if let LocalTrack::Pending { + publish_id: cur_publish_id, + muted, + } = &live_kit.screen_track + { + (*cur_publish_id != publish_id, *muted) + } else { + (true, false) + }; - // match publication { - // Ok(publication) => { - // if canceled { - // live_kit.room.unpublish_track(publication); - // } else { - // if muted { - // cx.executor().spawn(publication.set_mute(muted)).detach(); - // } - // live_kit.screen_track = LocalTrack::Published { - // track_publication: publication, - // muted, - // }; - // cx.notify(); - // } + match publication { + Ok(publication) => { + if canceled { + live_kit.room.unpublish_track(publication); + } else { + if muted { + cx.executor().spawn(publication.set_mute(muted)).detach(); + } + live_kit.screen_track = LocalTrack::Published { + track_publication: publication, + muted, + }; + cx.notify(); + } - // Audio::play_sound(Sound::StartScreenshare, cx); + Audio::play_sound(Sound::StartScreenshare, cx); - // Ok(()) - // } - // Err(error) => { - // if canceled { - // Ok(()) - // } else { - // live_kit.screen_track = LocalTrack::None; - // cx.notify(); - // Err(error) - // } - // } - // } - // })? - // }) + Ok(()) + } + Err(error) => { + if canceled { + Ok(()) + } else { + live_kit.screen_track = LocalTrack::None; + cx.notify(); + Err(error) + } + } + } + })? + }) } pub fn toggle_mute(&mut self, cx: &mut ModelContext) -> Result>> { - todo!() - // let should_mute = !self.is_muted(cx); - // if let Some(live_kit) = self.live_kit.as_mut() { - // if matches!(live_kit.microphone_track, LocalTrack::None) { - // return Ok(self.share_microphone(cx)); - // } + let should_mute = !self.is_muted(cx); + if let Some(live_kit) = self.live_kit.as_mut() { + if matches!(live_kit.microphone_track, LocalTrack::None) { + return Ok(self.share_microphone(cx)); + } - // let (ret_task, old_muted) = live_kit.set_mute(should_mute, cx)?; - // live_kit.muted_by_user = should_mute; + let (ret_task, old_muted) = live_kit.set_mute(should_mute, cx)?; + live_kit.muted_by_user = should_mute; - // if old_muted == true && live_kit.deafened == true { - // if let Some(task) = self.toggle_deafen(cx).ok() { - // task.detach(); - // } - // } + if old_muted == true && live_kit.deafened == true { + if let Some(task) = self.toggle_deafen(cx).ok() { + task.detach(); + } + } - // Ok(ret_task) - // } else { - // Err(anyhow!("LiveKit not started")) - // } + Ok(ret_task) + } else { + Err(anyhow!("LiveKit not started")) + } } pub fn toggle_deafen(&mut self, cx: &mut ModelContext) -> Result>> { - todo!() - // if let Some(live_kit) = self.live_kit.as_mut() { - // (*live_kit).deafened = !live_kit.deafened; + if let Some(live_kit) = self.live_kit.as_mut() { + (*live_kit).deafened = !live_kit.deafened; - // let mut tasks = Vec::with_capacity(self.remote_participants.len()); - // // Context notification is sent within set_mute itself. - // let mut mute_task = None; - // // When deafening, mute user's mic as well. - // // When undeafening, unmute user's mic unless it was manually muted prior to deafening. - // if live_kit.deafened || !live_kit.muted_by_user { - // mute_task = Some(live_kit.set_mute(live_kit.deafened, cx)?.0); - // }; - // for participant in self.remote_participants.values() { - // for track in live_kit - // .room - // .remote_audio_track_publications(&participant.user.id.to_string()) - // { - // let deafened = live_kit.deafened; - // tasks.push( - // cx.executor() - // .spawn_on_main(move || track.set_enabled(!deafened)), - // ); - // } - // } + let mut tasks = Vec::with_capacity(self.remote_participants.len()); + // Context notification is sent within set_mute itself. + let mut mute_task = None; + // When deafening, mute user's mic as well. + // When undeafening, unmute user's mic unless it was manually muted prior to deafening. + if live_kit.deafened || !live_kit.muted_by_user { + mute_task = Some(live_kit.set_mute(live_kit.deafened, cx)?.0); + }; + for participant in self.remote_participants.values() { + for track in live_kit + .room + .remote_audio_track_publications(&participant.user.id.to_string()) + { + let deafened = live_kit.deafened; + tasks.push( + cx.executor() + .spawn_on_main(move || track.set_enabled(!deafened)), + ); + } + } - // Ok(cx.executor().spawn_on_main(|| async { - // if let Some(mute_task) = mute_task { - // mute_task.await?; - // } - // for task in tasks { - // task.await?; - // } - // Ok(()) - // })) - // } else { - // Err(anyhow!("LiveKit not started")) - // } + Ok(cx.executor().spawn_on_main(|| async { + if let Some(mute_task) = mute_task { + mute_task.await?; + } + for task in tasks { + task.await?; + } + Ok(()) + })) + } else { + Err(anyhow!("LiveKit not started")) + } } pub fn unshare_screen(&mut self, cx: &mut ModelContext) -> Result<()> { @@ -1494,42 +1479,40 @@ impl Room { return Err(anyhow!("room is offline")); } - todo!() - // let live_kit = self - // .live_kit - // .as_mut() - // .ok_or_else(|| anyhow!("live-kit was not initialized"))?; - // match mem::take(&mut live_kit.screen_track) { - // LocalTrack::None => Err(anyhow!("screen was not shared")), - // LocalTrack::Pending { .. } => { - // cx.notify(); - // Ok(()) - // } - // LocalTrack::Published { - // track_publication, .. - // } => { - // live_kit.room.unpublish_track(track_publication); - // cx.notify(); + let live_kit = self + .live_kit + .as_mut() + .ok_or_else(|| anyhow!("live-kit was not initialized"))?; + match mem::take(&mut live_kit.screen_track) { + LocalTrack::None => Err(anyhow!("screen was not shared")), + LocalTrack::Pending { .. } => { + cx.notify(); + Ok(()) + } + LocalTrack::Published { + track_publication, .. + } => { + live_kit.room.unpublish_track(track_publication); + cx.notify(); - // Audio::play_sound(Sound::StopScreenshare, cx); - // Ok(()) - // } - // } + Audio::play_sound(Sound::StopScreenshare, cx); + Ok(()) + } + } } #[cfg(any(test, feature = "test-support"))] - pub fn set_display_sources(&self, sources: Vec) { - todo!() - // self.live_kit - // .as_ref() - // .unwrap() - // .room - // .set_display_sources(sources); + pub fn set_display_sources(&self, sources: Vec) { + self.live_kit + .as_ref() + .unwrap() + .room + .set_display_sources(sources); } } struct LiveKitRoom { - room: Arc, + room: Arc, screen_track: LocalTrack, microphone_track: LocalTrack, /// Tracks whether we're currently in a muted state due to auto-mute from deafening or manual mute performed by user. diff --git a/crates/editor/Cargo.toml b/crates/editor/Cargo.toml index 95d7820063..5113b5e7de 100644 --- a/crates/editor/Cargo.toml +++ b/crates/editor/Cargo.toml @@ -80,6 +80,7 @@ util = { path = "../util", features = ["test-support"] } project = { path = "../project", features = ["test-support"] } settings = { path = "../settings", features = ["test-support"] } workspace = { path = "../workspace", features = ["test-support"] } +multi_buffer = { path = "../multi_buffer", features = ["test-support"] } ctor.workspace = true env_logger.workspace = true diff --git a/crates/gpui2/src/subscription.rs b/crates/gpui2/src/subscription.rs index 3bf28792bb..c2799d2fe6 100644 --- a/crates/gpui2/src/subscription.rs +++ b/crates/gpui2/src/subscription.rs @@ -47,8 +47,8 @@ where subscribers.remove(&subscriber_id); if subscribers.is_empty() { lock.subscribers.remove(&emitter_key); - return; } + return; } // We didn't manage to remove the subscription, which means it was dropped diff --git a/crates/gpui2/src/view.rs b/crates/gpui2/src/view.rs index 89757434a9..b40514b40e 100644 --- a/crates/gpui2/src/view.rs +++ b/crates/gpui2/src/view.rs @@ -352,9 +352,12 @@ impl From> for AnyView { initialize: |view, cx| { cx.with_element_id(view.model.entity_id, |_, cx| { let view = view.clone().downcast::().unwrap(); - Box::new(AnyElement::new( - view.update(cx, |view, cx| Render::render(view, cx)), - )) + let element = view.update(cx, |view, cx| { + let mut element = AnyElement::new(view.render(cx)); + element.initialize(view, cx); + element + }); + Box::new(element) }) }, layout: |view, element, cx| { diff --git a/crates/gpui2/src/window.rs b/crates/gpui2/src/window.rs index 6c9c10af05..2c39815a4b 100644 --- a/crates/gpui2/src/window.rs +++ b/crates/gpui2/src/window.rs @@ -571,6 +571,12 @@ impl<'a> WindowContext<'a> { self.window.rem_size } + /// Sets the size of an em for the base font of the application. Adjusting this value allows the + /// UI to scale, just like zooming a web page. + pub fn set_rem_size(&mut self, rem_size: impl Into) { + self.window.rem_size = rem_size.into(); + } + /// The line height associated with the current text style. pub fn line_height(&self) -> Pixels { let rem_size = self.rem_size(); diff --git a/crates/language2/src/language2.rs b/crates/language2/src/language2.rs index 717a80619b..21746bf43c 100644 --- a/crates/language2/src/language2.rs +++ b/crates/language2/src/language2.rs @@ -42,7 +42,7 @@ use std::{ }, }; use syntax_map::SyntaxSnapshot; -use theme2::{SyntaxTheme, Theme}; +use theme2::{SyntaxTheme, ThemeVariant}; use tree_sitter::{self, Query}; use unicase::UniCase; use util::{http::HttpClient, paths::PathExt}; @@ -642,7 +642,7 @@ struct LanguageRegistryState { next_available_language_id: AvailableLanguageId, loading_languages: HashMap>>>>, subscription: (watch::Sender<()>, watch::Receiver<()>), - theme: Option>, + theme: Option>, version: usize, reload_count: usize, } @@ -743,11 +743,11 @@ impl LanguageRegistry { self.state.read().reload_count } - pub fn set_theme(&self, theme: Arc) { + pub fn set_theme(&self, theme: Arc) { let mut state = self.state.write(); state.theme = Some(theme.clone()); for language in &state.languages { - language.set_theme(&theme.syntax); + language.set_theme(&theme.syntax()); } } @@ -1048,7 +1048,7 @@ impl LanguageRegistryState { fn add(&mut self, language: Arc) { if let Some(theme) = self.theme.as_ref() { - language.set_theme(&theme.syntax); + language.set_theme(&theme.syntax()); } self.languages.push(language); self.version += 1; diff --git a/crates/live_kit_client/LiveKitBridge/Package.resolved b/crates/live_kit_client/LiveKitBridge/Package.resolved index b925bc8f0d..85ae088565 100644 --- a/crates/live_kit_client/LiveKitBridge/Package.resolved +++ b/crates/live_kit_client/LiveKitBridge/Package.resolved @@ -42,8 +42,8 @@ "repositoryURL": "https://github.com/apple/swift-protobuf.git", "state": { "branch": null, - "revision": "ce20dc083ee485524b802669890291c0d8090170", - "version": "1.22.1" + "revision": "0af9125c4eae12a4973fb66574c53a54962a9e1e", + "version": "1.21.0" } } ] diff --git a/crates/live_kit_client2/.cargo/config.toml b/crates/live_kit_client2/.cargo/config.toml new file mode 100644 index 0000000000..b33fe211bd --- /dev/null +++ b/crates/live_kit_client2/.cargo/config.toml @@ -0,0 +1,2 @@ +[live_kit_client_test] +rustflags = ["-C", "link-args=-ObjC"] diff --git a/crates/live_kit_client2/Cargo.toml b/crates/live_kit_client2/Cargo.toml new file mode 100644 index 0000000000..b5b45a8d45 --- /dev/null +++ b/crates/live_kit_client2/Cargo.toml @@ -0,0 +1,71 @@ +[package] +name = "live_kit_client2" +version = "0.1.0" +edition = "2021" +description = "Bindings to LiveKit Swift client SDK" +publish = false + +[lib] +path = "src/live_kit_client2.rs" +doctest = false + +[[example]] +name = "test_app" + +[features] +test-support = [ + "async-trait", + "collections/test-support", + "gpui2/test-support", + "live_kit_server", + "nanoid", +] + +[dependencies] +collections = { path = "../collections", optional = true } +gpui2 = { path = "../gpui2", optional = true } +live_kit_server = { path = "../live_kit_server", optional = true } +media = { path = "../media" } + +anyhow.workspace = true +async-broadcast = "0.4" +core-foundation = "0.9.3" +core-graphics = "0.22.3" +futures.workspace = true +log.workspace = true +parking_lot.workspace = true +postage.workspace = true + +async-trait = { workspace = true, optional = true } +nanoid = { version ="0.4", optional = true} + +[dev-dependencies] +collections = { path = "../collections", features = ["test-support"] } +gpui2 = { path = "../gpui2", features = ["test-support"] } +live_kit_server = { path = "../live_kit_server" } +media = { path = "../media" } +nanoid = "0.4" + +anyhow.workspace = true +async-trait.workspace = true +block = "0.1" +bytes = "1.2" +byteorder = "1.4" +cocoa = "0.24" +core-foundation = "0.9.3" +core-graphics = "0.22.3" +foreign-types = "0.3" +futures.workspace = true +hmac = "0.12" +jwt = "0.16" +objc = "0.2" +parking_lot.workspace = true +serde.workspace = true +serde_derive.workspace = true +sha2 = "0.10" +simplelog = "0.9" + +[build-dependencies] +serde.workspace = true +serde_derive.workspace = true +serde_json.workspace = true diff --git a/crates/live_kit_client2/LiveKitBridge2/Package.resolved b/crates/live_kit_client2/LiveKitBridge2/Package.resolved new file mode 100644 index 0000000000..b925bc8f0d --- /dev/null +++ b/crates/live_kit_client2/LiveKitBridge2/Package.resolved @@ -0,0 +1,52 @@ +{ + "object": { + "pins": [ + { + "package": "LiveKit", + "repositoryURL": "https://github.com/livekit/client-sdk-swift.git", + "state": { + "branch": null, + "revision": "7331b813a5ab8a95cfb81fb2b4ed10519428b9ff", + "version": "1.0.12" + } + }, + { + "package": "Promises", + "repositoryURL": "https://github.com/google/promises.git", + "state": { + "branch": null, + "revision": "ec957ccddbcc710ccc64c9dcbd4c7006fcf8b73a", + "version": "2.2.0" + } + }, + { + "package": "WebRTC", + "repositoryURL": "https://github.com/webrtc-sdk/Specs.git", + "state": { + "branch": null, + "revision": "2f6bab30c8df0fe59ab3e58bc99097f757f85f65", + "version": "104.5112.17" + } + }, + { + "package": "swift-log", + "repositoryURL": "https://github.com/apple/swift-log.git", + "state": { + "branch": null, + "revision": "32e8d724467f8fe623624570367e3d50c5638e46", + "version": "1.5.2" + } + }, + { + "package": "SwiftProtobuf", + "repositoryURL": "https://github.com/apple/swift-protobuf.git", + "state": { + "branch": null, + "revision": "ce20dc083ee485524b802669890291c0d8090170", + "version": "1.22.1" + } + } + ] + }, + "version": 1 +} diff --git a/crates/live_kit_client2/LiveKitBridge2/Package.swift b/crates/live_kit_client2/LiveKitBridge2/Package.swift new file mode 100644 index 0000000000..890eaa2f6d --- /dev/null +++ b/crates/live_kit_client2/LiveKitBridge2/Package.swift @@ -0,0 +1,27 @@ +// swift-tools-version: 5.5 + +import PackageDescription + +let package = Package( + name: "LiveKitBridge2", + platforms: [ + .macOS(.v10_15) + ], + products: [ + // Products define the executables and libraries a package produces, and make them visible to other packages. + .library( + name: "LiveKitBridge2", + type: .static, + targets: ["LiveKitBridge2"]), + ], + dependencies: [ + .package(url: "https://github.com/livekit/client-sdk-swift.git", .exact("1.0.12")), + ], + targets: [ + // Targets are the basic building blocks of a package. A target can define a module or a test suite. + // Targets can depend on other targets in this package, and on products in packages this package depends on. + .target( + name: "LiveKitBridge2", + dependencies: [.product(name: "LiveKit", package: "client-sdk-swift")]), + ] +) diff --git a/crates/live_kit_client2/LiveKitBridge2/README.md b/crates/live_kit_client2/LiveKitBridge2/README.md new file mode 100644 index 0000000000..1fceed8165 --- /dev/null +++ b/crates/live_kit_client2/LiveKitBridge2/README.md @@ -0,0 +1,3 @@ +# LiveKitBridge2 + +A description of this package. diff --git a/crates/live_kit_client2/LiveKitBridge2/Sources/LiveKitBridge2/LiveKitBridge2.swift b/crates/live_kit_client2/LiveKitBridge2/Sources/LiveKitBridge2/LiveKitBridge2.swift new file mode 100644 index 0000000000..5f22acf581 --- /dev/null +++ b/crates/live_kit_client2/LiveKitBridge2/Sources/LiveKitBridge2/LiveKitBridge2.swift @@ -0,0 +1,327 @@ +import Foundation +import LiveKit +import WebRTC +import ScreenCaptureKit + +class LKRoomDelegate: RoomDelegate { + var data: UnsafeRawPointer + var onDidDisconnect: @convention(c) (UnsafeRawPointer) -> Void + var onDidSubscribeToRemoteAudioTrack: @convention(c) (UnsafeRawPointer, CFString, CFString, UnsafeRawPointer, UnsafeRawPointer) -> Void + var onDidUnsubscribeFromRemoteAudioTrack: @convention(c) (UnsafeRawPointer, CFString, CFString) -> Void + var onMuteChangedFromRemoteAudioTrack: @convention(c) (UnsafeRawPointer, CFString, Bool) -> Void + var onActiveSpeakersChanged: @convention(c) (UnsafeRawPointer, CFArray) -> Void + var onDidSubscribeToRemoteVideoTrack: @convention(c) (UnsafeRawPointer, CFString, CFString, UnsafeRawPointer) -> Void + var onDidUnsubscribeFromRemoteVideoTrack: @convention(c) (UnsafeRawPointer, CFString, CFString) -> Void + + init( + data: UnsafeRawPointer, + onDidDisconnect: @escaping @convention(c) (UnsafeRawPointer) -> Void, + onDidSubscribeToRemoteAudioTrack: @escaping @convention(c) (UnsafeRawPointer, CFString, CFString, UnsafeRawPointer, UnsafeRawPointer) -> Void, + onDidUnsubscribeFromRemoteAudioTrack: @escaping @convention(c) (UnsafeRawPointer, CFString, CFString) -> Void, + onMuteChangedFromRemoteAudioTrack: @escaping @convention(c) (UnsafeRawPointer, CFString, Bool) -> Void, + onActiveSpeakersChanged: @convention(c) (UnsafeRawPointer, CFArray) -> Void, + onDidSubscribeToRemoteVideoTrack: @escaping @convention(c) (UnsafeRawPointer, CFString, CFString, UnsafeRawPointer) -> Void, + onDidUnsubscribeFromRemoteVideoTrack: @escaping @convention(c) (UnsafeRawPointer, CFString, CFString) -> Void) + { + self.data = data + self.onDidDisconnect = onDidDisconnect + self.onDidSubscribeToRemoteAudioTrack = onDidSubscribeToRemoteAudioTrack + self.onDidUnsubscribeFromRemoteAudioTrack = onDidUnsubscribeFromRemoteAudioTrack + self.onDidSubscribeToRemoteVideoTrack = onDidSubscribeToRemoteVideoTrack + self.onDidUnsubscribeFromRemoteVideoTrack = onDidUnsubscribeFromRemoteVideoTrack + self.onMuteChangedFromRemoteAudioTrack = onMuteChangedFromRemoteAudioTrack + self.onActiveSpeakersChanged = onActiveSpeakersChanged + } + + func room(_ room: Room, didUpdate connectionState: ConnectionState, oldValue: ConnectionState) { + if connectionState.isDisconnected { + self.onDidDisconnect(self.data) + } + } + + func room(_ room: Room, participant: RemoteParticipant, didSubscribe publication: RemoteTrackPublication, track: Track) { + if track.kind == .video { + self.onDidSubscribeToRemoteVideoTrack(self.data, participant.identity as CFString, track.sid! as CFString, Unmanaged.passUnretained(track).toOpaque()) + } else if track.kind == .audio { + self.onDidSubscribeToRemoteAudioTrack(self.data, participant.identity as CFString, track.sid! as CFString, Unmanaged.passUnretained(track).toOpaque(), Unmanaged.passUnretained(publication).toOpaque()) + } + } + + func room(_ room: Room, participant: Participant, didUpdate publication: TrackPublication, muted: Bool) { + if publication.kind == .audio { + self.onMuteChangedFromRemoteAudioTrack(self.data, publication.sid as CFString, muted) + } + } + + func room(_ room: Room, didUpdate speakers: [Participant]) { + guard let speaker_ids = speakers.compactMap({ $0.identity as CFString }) as CFArray? else { return } + self.onActiveSpeakersChanged(self.data, speaker_ids) + } + + func room(_ room: Room, participant: RemoteParticipant, didUnsubscribe publication: RemoteTrackPublication, track: Track) { + if track.kind == .video { + self.onDidUnsubscribeFromRemoteVideoTrack(self.data, participant.identity as CFString, track.sid! as CFString) + } else if track.kind == .audio { + self.onDidUnsubscribeFromRemoteAudioTrack(self.data, participant.identity as CFString, track.sid! as CFString) + } + } +} + +class LKVideoRenderer: NSObject, VideoRenderer { + var data: UnsafeRawPointer + var onFrame: @convention(c) (UnsafeRawPointer, CVPixelBuffer) -> Bool + var onDrop: @convention(c) (UnsafeRawPointer) -> Void + var adaptiveStreamIsEnabled: Bool = false + var adaptiveStreamSize: CGSize = .zero + weak var track: VideoTrack? + + init(data: UnsafeRawPointer, onFrame: @escaping @convention(c) (UnsafeRawPointer, CVPixelBuffer) -> Bool, onDrop: @escaping @convention(c) (UnsafeRawPointer) -> Void) { + self.data = data + self.onFrame = onFrame + self.onDrop = onDrop + } + + deinit { + self.onDrop(self.data) + } + + func setSize(_ size: CGSize) { + } + + func renderFrame(_ frame: RTCVideoFrame?) { + let buffer = frame?.buffer as? RTCCVPixelBuffer + if let pixelBuffer = buffer?.pixelBuffer { + if !self.onFrame(self.data, pixelBuffer) { + DispatchQueue.main.async { + self.track?.remove(videoRenderer: self) + } + } + } + } +} + +@_cdecl("LKRoomDelegateCreate") +public func LKRoomDelegateCreate( + data: UnsafeRawPointer, + onDidDisconnect: @escaping @convention(c) (UnsafeRawPointer) -> Void, + onDidSubscribeToRemoteAudioTrack: @escaping @convention(c) (UnsafeRawPointer, CFString, CFString, UnsafeRawPointer, UnsafeRawPointer) -> Void, + onDidUnsubscribeFromRemoteAudioTrack: @escaping @convention(c) (UnsafeRawPointer, CFString, CFString) -> Void, + onMuteChangedFromRemoteAudioTrack: @escaping @convention(c) (UnsafeRawPointer, CFString, Bool) -> Void, + onActiveSpeakerChanged: @escaping @convention(c) (UnsafeRawPointer, CFArray) -> Void, + onDidSubscribeToRemoteVideoTrack: @escaping @convention(c) (UnsafeRawPointer, CFString, CFString, UnsafeRawPointer) -> Void, + onDidUnsubscribeFromRemoteVideoTrack: @escaping @convention(c) (UnsafeRawPointer, CFString, CFString) -> Void +) -> UnsafeMutableRawPointer { + let delegate = LKRoomDelegate( + data: data, + onDidDisconnect: onDidDisconnect, + onDidSubscribeToRemoteAudioTrack: onDidSubscribeToRemoteAudioTrack, + onDidUnsubscribeFromRemoteAudioTrack: onDidUnsubscribeFromRemoteAudioTrack, + onMuteChangedFromRemoteAudioTrack: onMuteChangedFromRemoteAudioTrack, + onActiveSpeakersChanged: onActiveSpeakerChanged, + onDidSubscribeToRemoteVideoTrack: onDidSubscribeToRemoteVideoTrack, + onDidUnsubscribeFromRemoteVideoTrack: onDidUnsubscribeFromRemoteVideoTrack + ) + return Unmanaged.passRetained(delegate).toOpaque() +} + +@_cdecl("LKRoomCreate") +public func LKRoomCreate(delegate: UnsafeRawPointer) -> UnsafeMutableRawPointer { + let delegate = Unmanaged.fromOpaque(delegate).takeUnretainedValue() + return Unmanaged.passRetained(Room(delegate: delegate)).toOpaque() +} + +@_cdecl("LKRoomConnect") +public func LKRoomConnect(room: UnsafeRawPointer, url: CFString, token: CFString, callback: @escaping @convention(c) (UnsafeRawPointer, CFString?) -> Void, callback_data: UnsafeRawPointer) { + let room = Unmanaged.fromOpaque(room).takeUnretainedValue() + + room.connect(url as String, token as String).then { _ in + callback(callback_data, UnsafeRawPointer(nil) as! CFString?) + }.catch { error in + callback(callback_data, error.localizedDescription as CFString) + } +} + +@_cdecl("LKRoomDisconnect") +public func LKRoomDisconnect(room: UnsafeRawPointer) { + let room = Unmanaged.fromOpaque(room).takeUnretainedValue() + room.disconnect() +} + +@_cdecl("LKRoomPublishVideoTrack") +public func LKRoomPublishVideoTrack(room: UnsafeRawPointer, track: UnsafeRawPointer, callback: @escaping @convention(c) (UnsafeRawPointer, UnsafeMutableRawPointer?, CFString?) -> Void, callback_data: UnsafeRawPointer) { + let room = Unmanaged.fromOpaque(room).takeUnretainedValue() + let track = Unmanaged.fromOpaque(track).takeUnretainedValue() + room.localParticipant?.publishVideoTrack(track: track).then { publication in + callback(callback_data, Unmanaged.passRetained(publication).toOpaque(), nil) + }.catch { error in + callback(callback_data, nil, error.localizedDescription as CFString) + } +} + +@_cdecl("LKRoomPublishAudioTrack") +public func LKRoomPublishAudioTrack(room: UnsafeRawPointer, track: UnsafeRawPointer, callback: @escaping @convention(c) (UnsafeRawPointer, UnsafeMutableRawPointer?, CFString?) -> Void, callback_data: UnsafeRawPointer) { + let room = Unmanaged.fromOpaque(room).takeUnretainedValue() + let track = Unmanaged.fromOpaque(track).takeUnretainedValue() + room.localParticipant?.publishAudioTrack(track: track).then { publication in + callback(callback_data, Unmanaged.passRetained(publication).toOpaque(), nil) + }.catch { error in + callback(callback_data, nil, error.localizedDescription as CFString) + } +} + + +@_cdecl("LKRoomUnpublishTrack") +public func LKRoomUnpublishTrack(room: UnsafeRawPointer, publication: UnsafeRawPointer) { + let room = Unmanaged.fromOpaque(room).takeUnretainedValue() + let publication = Unmanaged.fromOpaque(publication).takeUnretainedValue() + let _ = room.localParticipant?.unpublish(publication: publication) +} + +@_cdecl("LKRoomAudioTracksForRemoteParticipant") +public func LKRoomAudioTracksForRemoteParticipant(room: UnsafeRawPointer, participantId: CFString) -> CFArray? { + let room = Unmanaged.fromOpaque(room).takeUnretainedValue() + + for (_, participant) in room.remoteParticipants { + if participant.identity == participantId as String { + return participant.audioTracks.compactMap { $0.track as? RemoteAudioTrack } as CFArray? + } + } + + return nil; +} + +@_cdecl("LKRoomAudioTrackPublicationsForRemoteParticipant") +public func LKRoomAudioTrackPublicationsForRemoteParticipant(room: UnsafeRawPointer, participantId: CFString) -> CFArray? { + let room = Unmanaged.fromOpaque(room).takeUnretainedValue() + + for (_, participant) in room.remoteParticipants { + if participant.identity == participantId as String { + return participant.audioTracks.compactMap { $0 as? RemoteTrackPublication } as CFArray? + } + } + + return nil; +} + +@_cdecl("LKRoomVideoTracksForRemoteParticipant") +public func LKRoomVideoTracksForRemoteParticipant(room: UnsafeRawPointer, participantId: CFString) -> CFArray? { + let room = Unmanaged.fromOpaque(room).takeUnretainedValue() + + for (_, participant) in room.remoteParticipants { + if participant.identity == participantId as String { + return participant.videoTracks.compactMap { $0.track as? RemoteVideoTrack } as CFArray? + } + } + + return nil; +} + +@_cdecl("LKLocalAudioTrackCreateTrack") +public func LKLocalAudioTrackCreateTrack() -> UnsafeMutableRawPointer { + let track = LocalAudioTrack.createTrack(options: AudioCaptureOptions( + echoCancellation: true, + noiseSuppression: true + )) + + return Unmanaged.passRetained(track).toOpaque() +} + + +@_cdecl("LKCreateScreenShareTrackForDisplay") +public func LKCreateScreenShareTrackForDisplay(display: UnsafeMutableRawPointer) -> UnsafeMutableRawPointer { + let display = Unmanaged.fromOpaque(display).takeUnretainedValue() + let track = LocalVideoTrack.createMacOSScreenShareTrack(source: display, preferredMethod: .legacy) + return Unmanaged.passRetained(track).toOpaque() +} + +@_cdecl("LKVideoRendererCreate") +public func LKVideoRendererCreate(data: UnsafeRawPointer, onFrame: @escaping @convention(c) (UnsafeRawPointer, CVPixelBuffer) -> Bool, onDrop: @escaping @convention(c) (UnsafeRawPointer) -> Void) -> UnsafeMutableRawPointer { + Unmanaged.passRetained(LKVideoRenderer(data: data, onFrame: onFrame, onDrop: onDrop)).toOpaque() +} + +@_cdecl("LKVideoTrackAddRenderer") +public func LKVideoTrackAddRenderer(track: UnsafeRawPointer, renderer: UnsafeRawPointer) { + let track = Unmanaged.fromOpaque(track).takeUnretainedValue() as! VideoTrack + let renderer = Unmanaged.fromOpaque(renderer).takeRetainedValue() + renderer.track = track + track.add(videoRenderer: renderer) +} + +@_cdecl("LKRemoteVideoTrackGetSid") +public func LKRemoteVideoTrackGetSid(track: UnsafeRawPointer) -> CFString { + let track = Unmanaged.fromOpaque(track).takeUnretainedValue() + return track.sid! as CFString +} + +@_cdecl("LKRemoteAudioTrackGetSid") +public func LKRemoteAudioTrackGetSid(track: UnsafeRawPointer) -> CFString { + let track = Unmanaged.fromOpaque(track).takeUnretainedValue() + return track.sid! as CFString +} + +@_cdecl("LKDisplaySources") +public func LKDisplaySources(data: UnsafeRawPointer, callback: @escaping @convention(c) (UnsafeRawPointer, CFArray?, CFString?) -> Void) { + MacOSScreenCapturer.sources(for: .display, includeCurrentApplication: false, preferredMethod: .legacy).then { displaySources in + callback(data, displaySources as CFArray, nil) + }.catch { error in + callback(data, nil, error.localizedDescription as CFString) + } +} + +@_cdecl("LKLocalTrackPublicationSetMute") +public func LKLocalTrackPublicationSetMute( + publication: UnsafeRawPointer, + muted: Bool, + on_complete: @escaping @convention(c) (UnsafeRawPointer, CFString?) -> Void, + callback_data: UnsafeRawPointer +) { + let publication = Unmanaged.fromOpaque(publication).takeUnretainedValue() + + if muted { + publication.mute().then { + on_complete(callback_data, nil) + }.catch { error in + on_complete(callback_data, error.localizedDescription as CFString) + } + } else { + publication.unmute().then { + on_complete(callback_data, nil) + }.catch { error in + on_complete(callback_data, error.localizedDescription as CFString) + } + } +} + +@_cdecl("LKRemoteTrackPublicationSetEnabled") +public func LKRemoteTrackPublicationSetEnabled( + publication: UnsafeRawPointer, + enabled: Bool, + on_complete: @escaping @convention(c) (UnsafeRawPointer, CFString?) -> Void, + callback_data: UnsafeRawPointer +) { + let publication = Unmanaged.fromOpaque(publication).takeUnretainedValue() + + publication.set(enabled: enabled).then { + on_complete(callback_data, nil) + }.catch { error in + on_complete(callback_data, error.localizedDescription as CFString) + } +} + +@_cdecl("LKRemoteTrackPublicationIsMuted") +public func LKRemoteTrackPublicationIsMuted( + publication: UnsafeRawPointer +) -> Bool { + let publication = Unmanaged.fromOpaque(publication).takeUnretainedValue() + + return publication.muted +} + +@_cdecl("LKRemoteTrackPublicationGetSid") +public func LKRemoteTrackPublicationGetSid( + publication: UnsafeRawPointer +) -> CFString { + let publication = Unmanaged.fromOpaque(publication).takeUnretainedValue() + + return publication.sid as CFString +} diff --git a/crates/live_kit_client2/build.rs b/crates/live_kit_client2/build.rs new file mode 100644 index 0000000000..b346b3168b --- /dev/null +++ b/crates/live_kit_client2/build.rs @@ -0,0 +1,172 @@ +use serde::Deserialize; +use std::{ + env, + path::{Path, PathBuf}, + process::Command, +}; + +const SWIFT_PACKAGE_NAME: &str = "LiveKitBridge2"; + +#[derive(Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct SwiftTargetInfo { + pub triple: String, + pub unversioned_triple: String, + pub module_triple: String, + pub swift_runtime_compatibility_version: String, + #[serde(rename = "librariesRequireRPath")] + pub libraries_require_rpath: bool, +} + +#[derive(Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct SwiftPaths { + pub runtime_library_paths: Vec, + pub runtime_library_import_paths: Vec, + pub runtime_resource_path: String, +} + +#[derive(Debug, Deserialize)] +pub struct SwiftTarget { + pub target: SwiftTargetInfo, + pub paths: SwiftPaths, +} + +const MACOS_TARGET_VERSION: &str = "10.15.7"; + +fn main() { + if cfg!(not(any(test, feature = "test-support"))) { + let swift_target = get_swift_target(); + + build_bridge(&swift_target); + link_swift_stdlib(&swift_target); + link_webrtc_framework(&swift_target); + + // Register exported Objective-C selectors, protocols, etc when building example binaries. + println!("cargo:rustc-link-arg=-Wl,-ObjC"); + } +} + +fn build_bridge(swift_target: &SwiftTarget) { + println!("cargo:rerun-if-env-changed=MACOSX_DEPLOYMENT_TARGET"); + println!("cargo:rerun-if-changed={}/Sources", SWIFT_PACKAGE_NAME); + println!( + "cargo:rerun-if-changed={}/Package.swift", + SWIFT_PACKAGE_NAME + ); + println!( + "cargo:rerun-if-changed={}/Package.resolved", + SWIFT_PACKAGE_NAME + ); + + let swift_package_root = swift_package_root(); + let swift_target_folder = swift_target_folder(); + if !Command::new("swift") + .arg("build") + .arg("--disable-automatic-resolution") + .args(["--configuration", &env::var("PROFILE").unwrap()]) + .args(["--triple", &swift_target.target.triple]) + .args(["--build-path".into(), swift_target_folder]) + .current_dir(&swift_package_root) + .status() + .unwrap() + .success() + { + panic!( + "Failed to compile swift package in {}", + swift_package_root.display() + ); + } + + println!( + "cargo:rustc-link-search=native={}", + swift_target.out_dir_path().display() + ); + println!("cargo:rustc-link-lib=static={}", SWIFT_PACKAGE_NAME); +} + +fn link_swift_stdlib(swift_target: &SwiftTarget) { + for path in &swift_target.paths.runtime_library_paths { + println!("cargo:rustc-link-search=native={}", path); + } +} + +fn link_webrtc_framework(swift_target: &SwiftTarget) { + let swift_out_dir_path = swift_target.out_dir_path(); + println!("cargo:rustc-link-lib=framework=WebRTC"); + println!( + "cargo:rustc-link-search=framework={}", + swift_out_dir_path.display() + ); + // Find WebRTC.framework as a sibling of the executable when running tests. + println!("cargo:rustc-link-arg=-Wl,-rpath,@executable_path"); + // Find WebRTC.framework in parent directory of the executable when running examples. + println!("cargo:rustc-link-arg=-Wl,-rpath,@executable_path/.."); + + let source_path = swift_out_dir_path.join("WebRTC.framework"); + let deps_dir_path = + PathBuf::from(env::var("OUT_DIR").unwrap()).join("../../../deps/WebRTC.framework"); + let target_dir_path = + PathBuf::from(env::var("OUT_DIR").unwrap()).join("../../../WebRTC.framework"); + copy_dir(&source_path, &deps_dir_path); + copy_dir(&source_path, &target_dir_path); +} + +fn get_swift_target() -> SwiftTarget { + let mut arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap(); + if arch == "aarch64" { + arch = "arm64".into(); + } + let target = format!("{}-apple-macosx{}", arch, MACOS_TARGET_VERSION); + + let swift_target_info_str = Command::new("swift") + .args(["-target", &target, "-print-target-info"]) + .output() + .unwrap() + .stdout; + + serde_json::from_slice(&swift_target_info_str).unwrap() +} + +fn swift_package_root() -> PathBuf { + env::current_dir().unwrap().join(SWIFT_PACKAGE_NAME) +} + +fn swift_target_folder() -> PathBuf { + env::current_dir() + .unwrap() + .join(format!("../../target/{SWIFT_PACKAGE_NAME}")) +} + +fn copy_dir(source: &Path, destination: &Path) { + assert!( + Command::new("rm") + .arg("-rf") + .arg(destination) + .status() + .unwrap() + .success(), + "could not remove {:?} before copying", + destination + ); + + assert!( + Command::new("cp") + .arg("-R") + .args([source, destination]) + .status() + .unwrap() + .success(), + "could not copy {:?} to {:?}", + source, + destination + ); +} + +impl SwiftTarget { + fn out_dir_path(&self) -> PathBuf { + swift_target_folder() + .join(&self.target.unversioned_triple) + .join(env::var("PROFILE").unwrap()) + } +} diff --git a/crates/live_kit_client2/examples/test_app.rs b/crates/live_kit_client2/examples/test_app.rs new file mode 100644 index 0000000000..ad10a4c95d --- /dev/null +++ b/crates/live_kit_client2/examples/test_app.rs @@ -0,0 +1,178 @@ +use std::{sync::Arc, time::Duration}; + +use futures::StreamExt; +use gpui2::KeyBinding; +use live_kit_client2::{ + LocalAudioTrack, LocalVideoTrack, RemoteAudioTrackUpdate, RemoteVideoTrackUpdate, Room, +}; +use live_kit_server::token::{self, VideoGrant}; +use log::LevelFilter; +use serde_derive::Deserialize; +use simplelog::SimpleLogger; + +#[derive(Deserialize, Debug, Clone, Copy, PartialEq, Eq, Default)] +struct Quit; + +fn main() { + SimpleLogger::init(LevelFilter::Info, Default::default()).expect("could not initialize logger"); + + gpui2::App::production(Arc::new(())).run(|cx| { + #[cfg(any(test, feature = "test-support"))] + println!("USING TEST LIVEKIT"); + + #[cfg(not(any(test, feature = "test-support")))] + println!("USING REAL LIVEKIT"); + + cx.activate(true); + + cx.on_action(quit); + cx.bind_keys([KeyBinding::new("cmd-q", Quit, None)]); + + // todo!() + // cx.set_menus(vec![Menu { + // name: "Zed", + // items: vec![MenuItem::Action { + // name: "Quit", + // action: Box::new(Quit), + // os_action: None, + // }], + // }]); + + let live_kit_url = std::env::var("LIVE_KIT_URL").unwrap_or("http://localhost:7880".into()); + let live_kit_key = std::env::var("LIVE_KIT_KEY").unwrap_or("devkey".into()); + let live_kit_secret = std::env::var("LIVE_KIT_SECRET").unwrap_or("secret".into()); + + cx.spawn_on_main(|cx| async move { + let user_a_token = token::create( + &live_kit_key, + &live_kit_secret, + Some("test-participant-1"), + VideoGrant::to_join("test-room"), + ) + .unwrap(); + let room_a = Room::new(); + room_a.connect(&live_kit_url, &user_a_token).await.unwrap(); + + let user2_token = token::create( + &live_kit_key, + &live_kit_secret, + Some("test-participant-2"), + VideoGrant::to_join("test-room"), + ) + .unwrap(); + let room_b = Room::new(); + room_b.connect(&live_kit_url, &user2_token).await.unwrap(); + + let mut audio_track_updates = room_b.remote_audio_track_updates(); + let audio_track = LocalAudioTrack::create(); + let audio_track_publication = room_a.publish_audio_track(audio_track).await.unwrap(); + + if let RemoteAudioTrackUpdate::Subscribed(track, _) = + audio_track_updates.next().await.unwrap() + { + let remote_tracks = room_b.remote_audio_tracks("test-participant-1"); + assert_eq!(remote_tracks.len(), 1); + assert_eq!(remote_tracks[0].publisher_id(), "test-participant-1"); + assert_eq!(track.publisher_id(), "test-participant-1"); + } else { + panic!("unexpected message"); + } + + audio_track_publication.set_mute(true).await.unwrap(); + + println!("waiting for mute changed!"); + if let RemoteAudioTrackUpdate::MuteChanged { track_id, muted } = + audio_track_updates.next().await.unwrap() + { + let remote_tracks = room_b.remote_audio_tracks("test-participant-1"); + assert_eq!(remote_tracks[0].sid(), track_id); + assert_eq!(muted, true); + } else { + panic!("unexpected message"); + } + + audio_track_publication.set_mute(false).await.unwrap(); + + if let RemoteAudioTrackUpdate::MuteChanged { track_id, muted } = + audio_track_updates.next().await.unwrap() + { + let remote_tracks = room_b.remote_audio_tracks("test-participant-1"); + assert_eq!(remote_tracks[0].sid(), track_id); + assert_eq!(muted, false); + } else { + panic!("unexpected message"); + } + + println!("Pausing for 5 seconds to test audio, make some noise!"); + let timer = cx.executor().timer(Duration::from_secs(5)); + timer.await; + let remote_audio_track = room_b + .remote_audio_tracks("test-participant-1") + .pop() + .unwrap(); + room_a.unpublish_track(audio_track_publication); + + // Clear out any active speakers changed messages + let mut next = audio_track_updates.next().await.unwrap(); + while let RemoteAudioTrackUpdate::ActiveSpeakersChanged { speakers } = next { + println!("Speakers changed: {:?}", speakers); + next = audio_track_updates.next().await.unwrap(); + } + + if let RemoteAudioTrackUpdate::Unsubscribed { + publisher_id, + track_id, + } = next + { + assert_eq!(publisher_id, "test-participant-1"); + assert_eq!(remote_audio_track.sid(), track_id); + assert_eq!(room_b.remote_audio_tracks("test-participant-1").len(), 0); + } else { + panic!("unexpected message"); + } + + let mut video_track_updates = room_b.remote_video_track_updates(); + let displays = room_a.display_sources().await.unwrap(); + let display = displays.into_iter().next().unwrap(); + + let local_video_track = LocalVideoTrack::screen_share_for_display(&display); + let local_video_track_publication = + room_a.publish_video_track(local_video_track).await.unwrap(); + + if let RemoteVideoTrackUpdate::Subscribed(track) = + video_track_updates.next().await.unwrap() + { + let remote_video_tracks = room_b.remote_video_tracks("test-participant-1"); + assert_eq!(remote_video_tracks.len(), 1); + assert_eq!(remote_video_tracks[0].publisher_id(), "test-participant-1"); + assert_eq!(track.publisher_id(), "test-participant-1"); + } else { + panic!("unexpected message"); + } + + let remote_video_track = room_b + .remote_video_tracks("test-participant-1") + .pop() + .unwrap(); + room_a.unpublish_track(local_video_track_publication); + if let RemoteVideoTrackUpdate::Unsubscribed { + publisher_id, + track_id, + } = video_track_updates.next().await.unwrap() + { + assert_eq!(publisher_id, "test-participant-1"); + assert_eq!(remote_video_track.sid(), track_id); + assert_eq!(room_b.remote_video_tracks("test-participant-1").len(), 0); + } else { + panic!("unexpected message"); + } + + cx.update(|cx| cx.quit()).ok(); + }) + .detach(); + }); +} + +fn quit(_: &Quit, cx: &mut gpui2::AppContext) { + cx.quit(); +} diff --git a/crates/live_kit_client2/src/live_kit_client2.rs b/crates/live_kit_client2/src/live_kit_client2.rs new file mode 100644 index 0000000000..47cc3873ff --- /dev/null +++ b/crates/live_kit_client2/src/live_kit_client2.rs @@ -0,0 +1,11 @@ +#[cfg(not(any(test, feature = "test-support")))] +pub mod prod; + +#[cfg(not(any(test, feature = "test-support")))] +pub use prod::*; + +#[cfg(any(test, feature = "test-support"))] +pub mod test; + +#[cfg(any(test, feature = "test-support"))] +pub use test::*; diff --git a/crates/live_kit_client2/src/prod.rs b/crates/live_kit_client2/src/prod.rs new file mode 100644 index 0000000000..b2b83e95fc --- /dev/null +++ b/crates/live_kit_client2/src/prod.rs @@ -0,0 +1,947 @@ +use anyhow::{anyhow, Context, Result}; +use core_foundation::{ + array::{CFArray, CFArrayRef}, + base::{CFRelease, CFRetain, TCFType}, + string::{CFString, CFStringRef}, +}; +use futures::{ + channel::{mpsc, oneshot}, + Future, +}; +pub use media::core_video::CVImageBuffer; +use media::core_video::CVImageBufferRef; +use parking_lot::Mutex; +use postage::watch; +use std::{ + ffi::c_void, + sync::{Arc, Weak}, +}; + +// SAFETY: Most live kit types are threadsafe: +// https://github.com/livekit/client-sdk-swift#thread-safety +macro_rules! pointer_type { + ($pointer_name:ident) => { + #[repr(transparent)] + #[derive(Copy, Clone, Debug)] + pub struct $pointer_name(pub *const std::ffi::c_void); + unsafe impl Send for $pointer_name {} + }; +} + +mod swift { + pointer_type!(Room); + pointer_type!(LocalAudioTrack); + pointer_type!(RemoteAudioTrack); + pointer_type!(LocalVideoTrack); + pointer_type!(RemoteVideoTrack); + pointer_type!(LocalTrackPublication); + pointer_type!(RemoteTrackPublication); + pointer_type!(MacOSDisplay); + pointer_type!(RoomDelegate); +} + +extern "C" { + fn LKRoomDelegateCreate( + callback_data: *mut c_void, + on_did_disconnect: extern "C" fn(callback_data: *mut c_void), + on_did_subscribe_to_remote_audio_track: extern "C" fn( + callback_data: *mut c_void, + publisher_id: CFStringRef, + track_id: CFStringRef, + remote_track: swift::RemoteAudioTrack, + remote_publication: swift::RemoteTrackPublication, + ), + on_did_unsubscribe_from_remote_audio_track: extern "C" fn( + callback_data: *mut c_void, + publisher_id: CFStringRef, + track_id: CFStringRef, + ), + on_mute_changed_from_remote_audio_track: extern "C" fn( + callback_data: *mut c_void, + track_id: CFStringRef, + muted: bool, + ), + on_active_speakers_changed: extern "C" fn( + callback_data: *mut c_void, + participants: CFArrayRef, + ), + on_did_subscribe_to_remote_video_track: extern "C" fn( + callback_data: *mut c_void, + publisher_id: CFStringRef, + track_id: CFStringRef, + remote_track: swift::RemoteVideoTrack, + ), + on_did_unsubscribe_from_remote_video_track: extern "C" fn( + callback_data: *mut c_void, + publisher_id: CFStringRef, + track_id: CFStringRef, + ), + ) -> swift::RoomDelegate; + + fn LKRoomCreate(delegate: swift::RoomDelegate) -> swift::Room; + fn LKRoomConnect( + room: swift::Room, + url: CFStringRef, + token: CFStringRef, + callback: extern "C" fn(*mut c_void, CFStringRef), + callback_data: *mut c_void, + ); + fn LKRoomDisconnect(room: swift::Room); + fn LKRoomPublishVideoTrack( + room: swift::Room, + track: swift::LocalVideoTrack, + callback: extern "C" fn(*mut c_void, swift::LocalTrackPublication, CFStringRef), + callback_data: *mut c_void, + ); + fn LKRoomPublishAudioTrack( + room: swift::Room, + track: swift::LocalAudioTrack, + callback: extern "C" fn(*mut c_void, swift::LocalTrackPublication, CFStringRef), + callback_data: *mut c_void, + ); + fn LKRoomUnpublishTrack(room: swift::Room, publication: swift::LocalTrackPublication); + + fn LKRoomAudioTracksForRemoteParticipant( + room: swift::Room, + participant_id: CFStringRef, + ) -> CFArrayRef; + + fn LKRoomAudioTrackPublicationsForRemoteParticipant( + room: swift::Room, + participant_id: CFStringRef, + ) -> CFArrayRef; + + fn LKRoomVideoTracksForRemoteParticipant( + room: swift::Room, + participant_id: CFStringRef, + ) -> CFArrayRef; + + fn LKVideoRendererCreate( + callback_data: *mut c_void, + on_frame: extern "C" fn(callback_data: *mut c_void, frame: CVImageBufferRef) -> bool, + on_drop: extern "C" fn(callback_data: *mut c_void), + ) -> *const c_void; + + fn LKRemoteAudioTrackGetSid(track: swift::RemoteAudioTrack) -> CFStringRef; + fn LKVideoTrackAddRenderer(track: swift::RemoteVideoTrack, renderer: *const c_void); + fn LKRemoteVideoTrackGetSid(track: swift::RemoteVideoTrack) -> CFStringRef; + + fn LKDisplaySources( + callback_data: *mut c_void, + callback: extern "C" fn( + callback_data: *mut c_void, + sources: CFArrayRef, + error: CFStringRef, + ), + ); + fn LKCreateScreenShareTrackForDisplay(display: swift::MacOSDisplay) -> swift::LocalVideoTrack; + fn LKLocalAudioTrackCreateTrack() -> swift::LocalAudioTrack; + + fn LKLocalTrackPublicationSetMute( + publication: swift::LocalTrackPublication, + muted: bool, + on_complete: extern "C" fn(callback_data: *mut c_void, error: CFStringRef), + callback_data: *mut c_void, + ); + + fn LKRemoteTrackPublicationSetEnabled( + publication: swift::RemoteTrackPublication, + enabled: bool, + on_complete: extern "C" fn(callback_data: *mut c_void, error: CFStringRef), + callback_data: *mut c_void, + ); + + fn LKRemoteTrackPublicationIsMuted(publication: swift::RemoteTrackPublication) -> bool; + fn LKRemoteTrackPublicationGetSid(publication: swift::RemoteTrackPublication) -> CFStringRef; +} + +pub type Sid = String; + +#[derive(Clone, Eq, PartialEq)] +pub enum ConnectionState { + Disconnected, + Connected { url: String, token: String }, +} + +pub struct Room { + native_room: Mutex, + connection: Mutex<( + watch::Sender, + watch::Receiver, + )>, + remote_audio_track_subscribers: Mutex>>, + remote_video_track_subscribers: Mutex>>, + _delegate: Mutex, +} + +trait AssertSendSync: Send {} +impl AssertSendSync for Room {} + +impl Room { + pub fn new() -> Arc { + Arc::new_cyclic(|weak_room| { + let delegate = RoomDelegate::new(weak_room.clone()); + Self { + native_room: Mutex::new(unsafe { LKRoomCreate(delegate.native_delegate) }), + connection: Mutex::new(watch::channel_with(ConnectionState::Disconnected)), + remote_audio_track_subscribers: Default::default(), + remote_video_track_subscribers: Default::default(), + _delegate: Mutex::new(delegate), + } + }) + } + + pub fn status(&self) -> watch::Receiver { + self.connection.lock().1.clone() + } + + pub fn connect(self: &Arc, url: &str, token: &str) -> impl Future> { + let url = CFString::new(url); + let token = CFString::new(token); + let (did_connect, tx, rx) = Self::build_done_callback(); + unsafe { + LKRoomConnect( + *self.native_room.lock(), + url.as_concrete_TypeRef(), + token.as_concrete_TypeRef(), + did_connect, + tx, + ) + } + + let this = self.clone(); + let url = url.to_string(); + let token = token.to_string(); + async move { + rx.await.unwrap().context("error connecting to room")?; + *this.connection.lock().0.borrow_mut() = ConnectionState::Connected { url, token }; + Ok(()) + } + } + + fn did_disconnect(&self) { + *self.connection.lock().0.borrow_mut() = ConnectionState::Disconnected; + } + + pub fn display_sources(self: &Arc) -> impl Future>> { + extern "C" fn callback(tx: *mut c_void, sources: CFArrayRef, error: CFStringRef) { + unsafe { + let tx = Box::from_raw(tx as *mut oneshot::Sender>>); + + if sources.is_null() { + let _ = tx.send(Err(anyhow!("{}", CFString::wrap_under_get_rule(error)))); + } else { + let sources = CFArray::wrap_under_get_rule(sources) + .into_iter() + .map(|source| MacOSDisplay::new(swift::MacOSDisplay(*source))) + .collect(); + + let _ = tx.send(Ok(sources)); + } + } + } + + let (tx, rx) = oneshot::channel(); + + unsafe { + LKDisplaySources(Box::into_raw(Box::new(tx)) as *mut _, callback); + } + + async move { rx.await.unwrap() } + } + + pub fn publish_video_track( + self: &Arc, + track: LocalVideoTrack, + ) -> impl Future> { + let (tx, rx) = oneshot::channel::>(); + extern "C" fn callback( + tx: *mut c_void, + publication: swift::LocalTrackPublication, + error: CFStringRef, + ) { + let tx = + unsafe { Box::from_raw(tx as *mut oneshot::Sender>) }; + if error.is_null() { + let _ = tx.send(Ok(LocalTrackPublication::new(publication))); + } else { + let error = unsafe { CFString::wrap_under_get_rule(error).to_string() }; + let _ = tx.send(Err(anyhow!(error))); + } + } + unsafe { + LKRoomPublishVideoTrack( + *self.native_room.lock(), + track.0, + callback, + Box::into_raw(Box::new(tx)) as *mut c_void, + ); + } + async { rx.await.unwrap().context("error publishing video track") } + } + + pub fn publish_audio_track( + self: &Arc, + track: LocalAudioTrack, + ) -> impl Future> { + let (tx, rx) = oneshot::channel::>(); + extern "C" fn callback( + tx: *mut c_void, + publication: swift::LocalTrackPublication, + error: CFStringRef, + ) { + let tx = + unsafe { Box::from_raw(tx as *mut oneshot::Sender>) }; + if error.is_null() { + let _ = tx.send(Ok(LocalTrackPublication::new(publication))); + } else { + let error = unsafe { CFString::wrap_under_get_rule(error).to_string() }; + let _ = tx.send(Err(anyhow!(error))); + } + } + unsafe { + LKRoomPublishAudioTrack( + *self.native_room.lock(), + track.0, + callback, + Box::into_raw(Box::new(tx)) as *mut c_void, + ); + } + async { rx.await.unwrap().context("error publishing audio track") } + } + + pub fn unpublish_track(&self, publication: LocalTrackPublication) { + unsafe { + LKRoomUnpublishTrack(*self.native_room.lock(), publication.0); + } + } + + pub fn remote_video_tracks(&self, participant_id: &str) -> Vec> { + unsafe { + let tracks = LKRoomVideoTracksForRemoteParticipant( + *self.native_room.lock(), + CFString::new(participant_id).as_concrete_TypeRef(), + ); + + if tracks.is_null() { + Vec::new() + } else { + let tracks = CFArray::wrap_under_get_rule(tracks); + tracks + .into_iter() + .map(|native_track| { + let native_track = swift::RemoteVideoTrack(*native_track); + let id = + CFString::wrap_under_get_rule(LKRemoteVideoTrackGetSid(native_track)) + .to_string(); + Arc::new(RemoteVideoTrack::new( + native_track, + id, + participant_id.into(), + )) + }) + .collect() + } + } + } + + pub fn remote_audio_tracks(&self, participant_id: &str) -> Vec> { + unsafe { + let tracks = LKRoomAudioTracksForRemoteParticipant( + *self.native_room.lock(), + CFString::new(participant_id).as_concrete_TypeRef(), + ); + + if tracks.is_null() { + Vec::new() + } else { + let tracks = CFArray::wrap_under_get_rule(tracks); + tracks + .into_iter() + .map(|native_track| { + let native_track = swift::RemoteAudioTrack(*native_track); + let id = + CFString::wrap_under_get_rule(LKRemoteAudioTrackGetSid(native_track)) + .to_string(); + Arc::new(RemoteAudioTrack::new( + native_track, + id, + participant_id.into(), + )) + }) + .collect() + } + } + } + + pub fn remote_audio_track_publications( + &self, + participant_id: &str, + ) -> Vec> { + unsafe { + let tracks = LKRoomAudioTrackPublicationsForRemoteParticipant( + *self.native_room.lock(), + CFString::new(participant_id).as_concrete_TypeRef(), + ); + + if tracks.is_null() { + Vec::new() + } else { + let tracks = CFArray::wrap_under_get_rule(tracks); + tracks + .into_iter() + .map(|native_track_publication| { + let native_track_publication = + swift::RemoteTrackPublication(*native_track_publication); + Arc::new(RemoteTrackPublication::new(native_track_publication)) + }) + .collect() + } + } + } + + pub fn remote_audio_track_updates(&self) -> mpsc::UnboundedReceiver { + let (tx, rx) = mpsc::unbounded(); + self.remote_audio_track_subscribers.lock().push(tx); + rx + } + + pub fn remote_video_track_updates(&self) -> mpsc::UnboundedReceiver { + let (tx, rx) = mpsc::unbounded(); + self.remote_video_track_subscribers.lock().push(tx); + rx + } + + fn did_subscribe_to_remote_audio_track( + &self, + track: RemoteAudioTrack, + publication: RemoteTrackPublication, + ) { + let track = Arc::new(track); + let publication = Arc::new(publication); + self.remote_audio_track_subscribers.lock().retain(|tx| { + tx.unbounded_send(RemoteAudioTrackUpdate::Subscribed( + track.clone(), + publication.clone(), + )) + .is_ok() + }); + } + + fn did_unsubscribe_from_remote_audio_track(&self, publisher_id: String, track_id: String) { + self.remote_audio_track_subscribers.lock().retain(|tx| { + tx.unbounded_send(RemoteAudioTrackUpdate::Unsubscribed { + publisher_id: publisher_id.clone(), + track_id: track_id.clone(), + }) + .is_ok() + }); + } + + fn mute_changed_from_remote_audio_track(&self, track_id: String, muted: bool) { + self.remote_audio_track_subscribers.lock().retain(|tx| { + tx.unbounded_send(RemoteAudioTrackUpdate::MuteChanged { + track_id: track_id.clone(), + muted, + }) + .is_ok() + }); + } + + // A vec of publisher IDs + fn active_speakers_changed(&self, speakers: Vec) { + self.remote_audio_track_subscribers + .lock() + .retain(move |tx| { + tx.unbounded_send(RemoteAudioTrackUpdate::ActiveSpeakersChanged { + speakers: speakers.clone(), + }) + .is_ok() + }); + } + + fn did_subscribe_to_remote_video_track(&self, track: RemoteVideoTrack) { + let track = Arc::new(track); + self.remote_video_track_subscribers.lock().retain(|tx| { + tx.unbounded_send(RemoteVideoTrackUpdate::Subscribed(track.clone())) + .is_ok() + }); + } + + fn did_unsubscribe_from_remote_video_track(&self, publisher_id: String, track_id: String) { + self.remote_video_track_subscribers.lock().retain(|tx| { + tx.unbounded_send(RemoteVideoTrackUpdate::Unsubscribed { + publisher_id: publisher_id.clone(), + track_id: track_id.clone(), + }) + .is_ok() + }); + } + + fn build_done_callback() -> ( + extern "C" fn(*mut c_void, CFStringRef), + *mut c_void, + oneshot::Receiver>, + ) { + let (tx, rx) = oneshot::channel(); + extern "C" fn done_callback(tx: *mut c_void, error: CFStringRef) { + let tx = unsafe { Box::from_raw(tx as *mut oneshot::Sender>) }; + if error.is_null() { + let _ = tx.send(Ok(())); + } else { + let error = unsafe { CFString::wrap_under_get_rule(error).to_string() }; + let _ = tx.send(Err(anyhow!(error))); + } + } + ( + done_callback, + Box::into_raw(Box::new(tx)) as *mut c_void, + rx, + ) + } + + pub fn set_display_sources(&self, _: Vec) { + unreachable!("This is a test-only function") + } +} + +impl Drop for Room { + fn drop(&mut self) { + unsafe { + let native_room = &*self.native_room.lock(); + LKRoomDisconnect(*native_room); + CFRelease(native_room.0); + } + } +} + +struct RoomDelegate { + native_delegate: swift::RoomDelegate, + _weak_room: Weak, +} + +impl RoomDelegate { + fn new(weak_room: Weak) -> Self { + let native_delegate = unsafe { + LKRoomDelegateCreate( + weak_room.as_ptr() as *mut c_void, + Self::on_did_disconnect, + Self::on_did_subscribe_to_remote_audio_track, + Self::on_did_unsubscribe_from_remote_audio_track, + Self::on_mute_change_from_remote_audio_track, + Self::on_active_speakers_changed, + Self::on_did_subscribe_to_remote_video_track, + Self::on_did_unsubscribe_from_remote_video_track, + ) + }; + Self { + native_delegate, + _weak_room: weak_room, + } + } + + extern "C" fn on_did_disconnect(room: *mut c_void) { + let room = unsafe { Weak::from_raw(room as *mut Room) }; + if let Some(room) = room.upgrade() { + room.did_disconnect(); + } + let _ = Weak::into_raw(room); + } + + extern "C" fn on_did_subscribe_to_remote_audio_track( + room: *mut c_void, + publisher_id: CFStringRef, + track_id: CFStringRef, + track: swift::RemoteAudioTrack, + publication: swift::RemoteTrackPublication, + ) { + let room = unsafe { Weak::from_raw(room as *mut Room) }; + let publisher_id = unsafe { CFString::wrap_under_get_rule(publisher_id).to_string() }; + let track_id = unsafe { CFString::wrap_under_get_rule(track_id).to_string() }; + let track = RemoteAudioTrack::new(track, track_id, publisher_id); + let publication = RemoteTrackPublication::new(publication); + if let Some(room) = room.upgrade() { + room.did_subscribe_to_remote_audio_track(track, publication); + } + let _ = Weak::into_raw(room); + } + + extern "C" fn on_did_unsubscribe_from_remote_audio_track( + room: *mut c_void, + publisher_id: CFStringRef, + track_id: CFStringRef, + ) { + let room = unsafe { Weak::from_raw(room as *mut Room) }; + let publisher_id = unsafe { CFString::wrap_under_get_rule(publisher_id).to_string() }; + let track_id = unsafe { CFString::wrap_under_get_rule(track_id).to_string() }; + if let Some(room) = room.upgrade() { + room.did_unsubscribe_from_remote_audio_track(publisher_id, track_id); + } + let _ = Weak::into_raw(room); + } + + extern "C" fn on_mute_change_from_remote_audio_track( + room: *mut c_void, + track_id: CFStringRef, + muted: bool, + ) { + let room = unsafe { Weak::from_raw(room as *mut Room) }; + let track_id = unsafe { CFString::wrap_under_get_rule(track_id).to_string() }; + if let Some(room) = room.upgrade() { + room.mute_changed_from_remote_audio_track(track_id, muted); + } + let _ = Weak::into_raw(room); + } + + extern "C" fn on_active_speakers_changed(room: *mut c_void, participants: CFArrayRef) { + if participants.is_null() { + return; + } + + let room = unsafe { Weak::from_raw(room as *mut Room) }; + let speakers = unsafe { + CFArray::wrap_under_get_rule(participants) + .into_iter() + .map( + |speaker: core_foundation::base::ItemRef<'_, *const c_void>| { + CFString::wrap_under_get_rule(*speaker as CFStringRef).to_string() + }, + ) + .collect() + }; + + if let Some(room) = room.upgrade() { + room.active_speakers_changed(speakers); + } + let _ = Weak::into_raw(room); + } + + extern "C" fn on_did_subscribe_to_remote_video_track( + room: *mut c_void, + publisher_id: CFStringRef, + track_id: CFStringRef, + track: swift::RemoteVideoTrack, + ) { + let room = unsafe { Weak::from_raw(room as *mut Room) }; + let publisher_id = unsafe { CFString::wrap_under_get_rule(publisher_id).to_string() }; + let track_id = unsafe { CFString::wrap_under_get_rule(track_id).to_string() }; + let track = RemoteVideoTrack::new(track, track_id, publisher_id); + if let Some(room) = room.upgrade() { + room.did_subscribe_to_remote_video_track(track); + } + let _ = Weak::into_raw(room); + } + + extern "C" fn on_did_unsubscribe_from_remote_video_track( + room: *mut c_void, + publisher_id: CFStringRef, + track_id: CFStringRef, + ) { + let room = unsafe { Weak::from_raw(room as *mut Room) }; + let publisher_id = unsafe { CFString::wrap_under_get_rule(publisher_id).to_string() }; + let track_id = unsafe { CFString::wrap_under_get_rule(track_id).to_string() }; + if let Some(room) = room.upgrade() { + room.did_unsubscribe_from_remote_video_track(publisher_id, track_id); + } + let _ = Weak::into_raw(room); + } +} + +impl Drop for RoomDelegate { + fn drop(&mut self) { + unsafe { + CFRelease(self.native_delegate.0); + } + } +} + +pub struct LocalAudioTrack(swift::LocalAudioTrack); + +impl LocalAudioTrack { + pub fn create() -> Self { + Self(unsafe { LKLocalAudioTrackCreateTrack() }) + } +} + +impl Drop for LocalAudioTrack { + fn drop(&mut self) { + unsafe { CFRelease(self.0 .0) } + } +} + +pub struct LocalVideoTrack(swift::LocalVideoTrack); + +impl LocalVideoTrack { + pub fn screen_share_for_display(display: &MacOSDisplay) -> Self { + Self(unsafe { LKCreateScreenShareTrackForDisplay(display.0) }) + } +} + +impl Drop for LocalVideoTrack { + fn drop(&mut self) { + unsafe { CFRelease(self.0 .0) } + } +} + +pub struct LocalTrackPublication(swift::LocalTrackPublication); + +impl LocalTrackPublication { + pub fn new(native_track_publication: swift::LocalTrackPublication) -> Self { + unsafe { + CFRetain(native_track_publication.0); + } + Self(native_track_publication) + } + + pub fn set_mute(&self, muted: bool) -> impl Future> { + let (tx, rx) = futures::channel::oneshot::channel(); + + extern "C" fn complete_callback(callback_data: *mut c_void, error: CFStringRef) { + let tx = unsafe { Box::from_raw(callback_data as *mut oneshot::Sender>) }; + if error.is_null() { + tx.send(Ok(())).ok(); + } else { + let error = unsafe { CFString::wrap_under_get_rule(error).to_string() }; + tx.send(Err(anyhow!(error))).ok(); + } + } + + unsafe { + LKLocalTrackPublicationSetMute( + self.0, + muted, + complete_callback, + Box::into_raw(Box::new(tx)) as *mut c_void, + ) + } + + async move { rx.await.unwrap() } + } +} + +impl Drop for LocalTrackPublication { + fn drop(&mut self) { + unsafe { CFRelease(self.0 .0) } + } +} + +pub struct RemoteTrackPublication { + native_publication: Mutex, +} + +impl RemoteTrackPublication { + pub fn new(native_track_publication: swift::RemoteTrackPublication) -> Self { + unsafe { + CFRetain(native_track_publication.0); + } + Self { + native_publication: Mutex::new(native_track_publication), + } + } + + pub fn sid(&self) -> String { + unsafe { + CFString::wrap_under_get_rule(LKRemoteTrackPublicationGetSid( + *self.native_publication.lock(), + )) + .to_string() + } + } + + pub fn is_muted(&self) -> bool { + unsafe { LKRemoteTrackPublicationIsMuted(*self.native_publication.lock()) } + } + + pub fn set_enabled(&self, enabled: bool) -> impl Future> { + let (tx, rx) = futures::channel::oneshot::channel(); + + extern "C" fn complete_callback(callback_data: *mut c_void, error: CFStringRef) { + let tx = unsafe { Box::from_raw(callback_data as *mut oneshot::Sender>) }; + if error.is_null() { + tx.send(Ok(())).ok(); + } else { + let error = unsafe { CFString::wrap_under_get_rule(error).to_string() }; + tx.send(Err(anyhow!(error))).ok(); + } + } + + unsafe { + LKRemoteTrackPublicationSetEnabled( + *self.native_publication.lock(), + enabled, + complete_callback, + Box::into_raw(Box::new(tx)) as *mut c_void, + ) + } + + async move { rx.await.unwrap() } + } +} + +impl Drop for RemoteTrackPublication { + fn drop(&mut self) { + unsafe { CFRelease((*self.native_publication.lock()).0) } + } +} + +#[derive(Debug)] +pub struct RemoteAudioTrack { + native_track: Mutex, + sid: Sid, + publisher_id: String, +} + +impl RemoteAudioTrack { + fn new(native_track: swift::RemoteAudioTrack, sid: Sid, publisher_id: String) -> Self { + unsafe { + CFRetain(native_track.0); + } + Self { + native_track: Mutex::new(native_track), + sid, + publisher_id, + } + } + + pub fn sid(&self) -> &str { + &self.sid + } + + pub fn publisher_id(&self) -> &str { + &self.publisher_id + } + + pub fn enable(&self) -> impl Future> { + async { Ok(()) } + } + + pub fn disable(&self) -> impl Future> { + async { Ok(()) } + } +} + +impl Drop for RemoteAudioTrack { + fn drop(&mut self) { + unsafe { CFRelease(self.native_track.lock().0) } + } +} + +#[derive(Debug)] +pub struct RemoteVideoTrack { + native_track: Mutex, + sid: Sid, + publisher_id: String, +} + +impl RemoteVideoTrack { + fn new(native_track: swift::RemoteVideoTrack, sid: Sid, publisher_id: String) -> Self { + unsafe { + CFRetain(native_track.0); + } + Self { + native_track: Mutex::new(native_track), + sid, + publisher_id, + } + } + + pub fn sid(&self) -> &str { + &self.sid + } + + pub fn publisher_id(&self) -> &str { + &self.publisher_id + } + + pub fn frames(&self) -> async_broadcast::Receiver { + extern "C" fn on_frame(callback_data: *mut c_void, frame: CVImageBufferRef) -> bool { + unsafe { + let tx = Box::from_raw(callback_data as *mut async_broadcast::Sender); + let buffer = CVImageBuffer::wrap_under_get_rule(frame); + let result = tx.try_broadcast(Frame(buffer)); + let _ = Box::into_raw(tx); + match result { + Ok(_) => true, + Err(async_broadcast::TrySendError::Closed(_)) + | Err(async_broadcast::TrySendError::Inactive(_)) => { + log::warn!("no active receiver for frame"); + false + } + Err(async_broadcast::TrySendError::Full(_)) => { + log::warn!("skipping frame as receiver is not keeping up"); + true + } + } + } + } + + extern "C" fn on_drop(callback_data: *mut c_void) { + unsafe { + let _ = Box::from_raw(callback_data as *mut async_broadcast::Sender); + } + } + + let (tx, rx) = async_broadcast::broadcast(64); + unsafe { + let renderer = LKVideoRendererCreate( + Box::into_raw(Box::new(tx)) as *mut c_void, + on_frame, + on_drop, + ); + LKVideoTrackAddRenderer(*self.native_track.lock(), renderer); + rx + } + } +} + +impl Drop for RemoteVideoTrack { + fn drop(&mut self) { + unsafe { CFRelease(self.native_track.lock().0) } + } +} + +pub enum RemoteVideoTrackUpdate { + Subscribed(Arc), + Unsubscribed { publisher_id: Sid, track_id: Sid }, +} + +pub enum RemoteAudioTrackUpdate { + ActiveSpeakersChanged { speakers: Vec }, + MuteChanged { track_id: Sid, muted: bool }, + Subscribed(Arc, Arc), + Unsubscribed { publisher_id: Sid, track_id: Sid }, +} + +pub struct MacOSDisplay(swift::MacOSDisplay); + +impl MacOSDisplay { + fn new(ptr: swift::MacOSDisplay) -> Self { + unsafe { + CFRetain(ptr.0); + } + Self(ptr) + } +} + +impl Drop for MacOSDisplay { + fn drop(&mut self) { + unsafe { CFRelease(self.0 .0) } + } +} + +#[derive(Clone)] +pub struct Frame(CVImageBuffer); + +impl Frame { + pub fn width(&self) -> usize { + self.0.width() + } + + pub fn height(&self) -> usize { + self.0.height() + } + + pub fn image(&self) -> CVImageBuffer { + self.0.clone() + } +} diff --git a/crates/live_kit_client2/src/test.rs b/crates/live_kit_client2/src/test.rs new file mode 100644 index 0000000000..f1c3d39b8e --- /dev/null +++ b/crates/live_kit_client2/src/test.rs @@ -0,0 +1,651 @@ +use anyhow::{anyhow, Context, Result}; +use async_trait::async_trait; +use collections::{BTreeMap, HashMap}; +use futures::Stream; +use gpui2::Executor; +use live_kit_server::token; +use media::core_video::CVImageBuffer; +use parking_lot::Mutex; +use postage::watch; +use std::{future::Future, mem, sync::Arc}; + +static SERVERS: Mutex>> = Mutex::new(BTreeMap::new()); + +pub struct TestServer { + pub url: String, + pub api_key: String, + pub secret_key: String, + rooms: Mutex>, + executor: Arc, +} + +impl TestServer { + pub fn create( + url: String, + api_key: String, + secret_key: String, + executor: Arc, + ) -> Result> { + let mut servers = SERVERS.lock(); + if servers.contains_key(&url) { + Err(anyhow!("a server with url {:?} already exists", url)) + } else { + let server = Arc::new(TestServer { + url: url.clone(), + api_key, + secret_key, + rooms: Default::default(), + executor, + }); + servers.insert(url, server.clone()); + Ok(server) + } + } + + fn get(url: &str) -> Result> { + Ok(SERVERS + .lock() + .get(url) + .ok_or_else(|| anyhow!("no server found for url"))? + .clone()) + } + + pub fn teardown(&self) -> Result<()> { + SERVERS + .lock() + .remove(&self.url) + .ok_or_else(|| anyhow!("server with url {:?} does not exist", self.url))?; + Ok(()) + } + + pub fn create_api_client(&self) -> TestApiClient { + TestApiClient { + url: self.url.clone(), + } + } + + pub async fn create_room(&self, room: String) -> Result<()> { + self.executor.simulate_random_delay().await; + let mut server_rooms = self.rooms.lock(); + if server_rooms.contains_key(&room) { + Err(anyhow!("room {:?} already exists", room)) + } else { + server_rooms.insert(room, Default::default()); + Ok(()) + } + } + + async fn delete_room(&self, room: String) -> Result<()> { + // TODO: clear state associated with all `Room`s. + self.executor.simulate_random_delay().await; + let mut server_rooms = self.rooms.lock(); + server_rooms + .remove(&room) + .ok_or_else(|| anyhow!("room {:?} does not exist", room))?; + Ok(()) + } + + async fn join_room(&self, token: String, client_room: Arc) -> Result<()> { + self.executor.simulate_random_delay().await; + let claims = live_kit_server::token::validate(&token, &self.secret_key)?; + let identity = claims.sub.unwrap().to_string(); + let room_name = claims.video.room.unwrap(); + let mut server_rooms = self.rooms.lock(); + let room = (*server_rooms).entry(room_name.to_string()).or_default(); + + if room.client_rooms.contains_key(&identity) { + Err(anyhow!( + "{:?} attempted to join room {:?} twice", + identity, + room_name + )) + } else { + for track in &room.video_tracks { + client_room + .0 + .lock() + .video_track_updates + .0 + .try_broadcast(RemoteVideoTrackUpdate::Subscribed(track.clone())) + .unwrap(); + } + room.client_rooms.insert(identity, client_room); + Ok(()) + } + } + + async fn leave_room(&self, token: String) -> Result<()> { + self.executor.simulate_random_delay().await; + let claims = live_kit_server::token::validate(&token, &self.secret_key)?; + let identity = claims.sub.unwrap().to_string(); + let room_name = claims.video.room.unwrap(); + let mut server_rooms = self.rooms.lock(); + let room = server_rooms + .get_mut(&*room_name) + .ok_or_else(|| anyhow!("room {} does not exist", room_name))?; + room.client_rooms.remove(&identity).ok_or_else(|| { + anyhow!( + "{:?} attempted to leave room {:?} before joining it", + identity, + room_name + ) + })?; + Ok(()) + } + + async fn remove_participant(&self, room_name: String, identity: String) -> Result<()> { + // TODO: clear state associated with the `Room`. + + self.executor.simulate_random_delay().await; + let mut server_rooms = self.rooms.lock(); + let room = server_rooms + .get_mut(&room_name) + .ok_or_else(|| anyhow!("room {} does not exist", room_name))?; + room.client_rooms.remove(&identity).ok_or_else(|| { + anyhow!( + "participant {:?} did not join room {:?}", + identity, + room_name + ) + })?; + Ok(()) + } + + pub async fn disconnect_client(&self, client_identity: String) { + self.executor.simulate_random_delay().await; + let mut server_rooms = self.rooms.lock(); + for room in server_rooms.values_mut() { + if let Some(room) = room.client_rooms.remove(&client_identity) { + *room.0.lock().connection.0.borrow_mut() = ConnectionState::Disconnected; + } + } + } + + async fn publish_video_track(&self, token: String, local_track: LocalVideoTrack) -> Result<()> { + self.executor.simulate_random_delay().await; + let claims = live_kit_server::token::validate(&token, &self.secret_key)?; + let identity = claims.sub.unwrap().to_string(); + let room_name = claims.video.room.unwrap(); + + let mut server_rooms = self.rooms.lock(); + let room = server_rooms + .get_mut(&*room_name) + .ok_or_else(|| anyhow!("room {} does not exist", room_name))?; + + let track = Arc::new(RemoteVideoTrack { + sid: nanoid::nanoid!(17), + publisher_id: identity.clone(), + frames_rx: local_track.frames_rx.clone(), + }); + + room.video_tracks.push(track.clone()); + + for (id, client_room) in &room.client_rooms { + if *id != identity { + let _ = client_room + .0 + .lock() + .video_track_updates + .0 + .try_broadcast(RemoteVideoTrackUpdate::Subscribed(track.clone())) + .unwrap(); + } + } + + Ok(()) + } + + async fn publish_audio_track( + &self, + token: String, + _local_track: &LocalAudioTrack, + ) -> Result<()> { + self.executor.simulate_random_delay().await; + let claims = live_kit_server::token::validate(&token, &self.secret_key)?; + let identity = claims.sub.unwrap().to_string(); + let room_name = claims.video.room.unwrap(); + + let mut server_rooms = self.rooms.lock(); + let room = server_rooms + .get_mut(&*room_name) + .ok_or_else(|| anyhow!("room {} does not exist", room_name))?; + + let track = Arc::new(RemoteAudioTrack { + sid: nanoid::nanoid!(17), + publisher_id: identity.clone(), + }); + + let publication = Arc::new(RemoteTrackPublication); + + room.audio_tracks.push(track.clone()); + + for (id, client_room) in &room.client_rooms { + if *id != identity { + let _ = client_room + .0 + .lock() + .audio_track_updates + .0 + .try_broadcast(RemoteAudioTrackUpdate::Subscribed( + track.clone(), + publication.clone(), + )) + .unwrap(); + } + } + + Ok(()) + } + + fn video_tracks(&self, token: String) -> Result>> { + let claims = live_kit_server::token::validate(&token, &self.secret_key)?; + let room_name = claims.video.room.unwrap(); + + let mut server_rooms = self.rooms.lock(); + let room = server_rooms + .get_mut(&*room_name) + .ok_or_else(|| anyhow!("room {} does not exist", room_name))?; + Ok(room.video_tracks.clone()) + } + + fn audio_tracks(&self, token: String) -> Result>> { + let claims = live_kit_server::token::validate(&token, &self.secret_key)?; + let room_name = claims.video.room.unwrap(); + + let mut server_rooms = self.rooms.lock(); + let room = server_rooms + .get_mut(&*room_name) + .ok_or_else(|| anyhow!("room {} does not exist", room_name))?; + Ok(room.audio_tracks.clone()) + } +} + +#[derive(Default)] +struct TestServerRoom { + client_rooms: HashMap>, + video_tracks: Vec>, + audio_tracks: Vec>, +} + +impl TestServerRoom {} + +pub struct TestApiClient { + url: String, +} + +#[async_trait] +impl live_kit_server::api::Client for TestApiClient { + fn url(&self) -> &str { + &self.url + } + + async fn create_room(&self, name: String) -> Result<()> { + let server = TestServer::get(&self.url)?; + server.create_room(name).await?; + Ok(()) + } + + async fn delete_room(&self, name: String) -> Result<()> { + let server = TestServer::get(&self.url)?; + server.delete_room(name).await?; + Ok(()) + } + + async fn remove_participant(&self, room: String, identity: String) -> Result<()> { + let server = TestServer::get(&self.url)?; + server.remove_participant(room, identity).await?; + Ok(()) + } + + fn room_token(&self, room: &str, identity: &str) -> Result { + let server = TestServer::get(&self.url)?; + token::create( + &server.api_key, + &server.secret_key, + Some(identity), + token::VideoGrant::to_join(room), + ) + } + + fn guest_token(&self, room: &str, identity: &str) -> Result { + let server = TestServer::get(&self.url)?; + token::create( + &server.api_key, + &server.secret_key, + Some(identity), + token::VideoGrant::for_guest(room), + ) + } +} + +pub type Sid = String; + +struct RoomState { + connection: ( + watch::Sender, + watch::Receiver, + ), + display_sources: Vec, + audio_track_updates: ( + async_broadcast::Sender, + async_broadcast::Receiver, + ), + video_track_updates: ( + async_broadcast::Sender, + async_broadcast::Receiver, + ), +} + +#[derive(Clone, Eq, PartialEq)] +pub enum ConnectionState { + Disconnected, + Connected { url: String, token: String }, +} + +pub struct Room(Mutex); + +impl Room { + pub fn new() -> Arc { + Arc::new(Self(Mutex::new(RoomState { + connection: watch::channel_with(ConnectionState::Disconnected), + display_sources: Default::default(), + video_track_updates: async_broadcast::broadcast(128), + audio_track_updates: async_broadcast::broadcast(128), + }))) + } + + pub fn status(&self) -> watch::Receiver { + self.0.lock().connection.1.clone() + } + + pub fn connect(self: &Arc, url: &str, token: &str) -> impl Future> { + let this = self.clone(); + let url = url.to_string(); + let token = token.to_string(); + async move { + let server = TestServer::get(&url)?; + server + .join_room(token.clone(), this.clone()) + .await + .context("room join")?; + *this.0.lock().connection.0.borrow_mut() = ConnectionState::Connected { url, token }; + Ok(()) + } + } + + pub fn display_sources(self: &Arc) -> impl Future>> { + let this = self.clone(); + async move { + let server = this.test_server(); + server.executor.simulate_random_delay().await; + Ok(this.0.lock().display_sources.clone()) + } + } + + pub fn publish_video_track( + self: &Arc, + track: LocalVideoTrack, + ) -> impl Future> { + let this = self.clone(); + let track = track.clone(); + async move { + this.test_server() + .publish_video_track(this.token(), track) + .await?; + Ok(LocalTrackPublication) + } + } + pub fn publish_audio_track( + self: &Arc, + track: LocalAudioTrack, + ) -> impl Future> { + let this = self.clone(); + let track = track.clone(); + async move { + this.test_server() + .publish_audio_track(this.token(), &track) + .await?; + Ok(LocalTrackPublication) + } + } + + pub fn unpublish_track(&self, _publication: LocalTrackPublication) {} + + pub fn remote_audio_tracks(&self, publisher_id: &str) -> Vec> { + if !self.is_connected() { + return Vec::new(); + } + + self.test_server() + .audio_tracks(self.token()) + .unwrap() + .into_iter() + .filter(|track| track.publisher_id() == publisher_id) + .collect() + } + + pub fn remote_audio_track_publications( + &self, + publisher_id: &str, + ) -> Vec> { + if !self.is_connected() { + return Vec::new(); + } + + self.test_server() + .audio_tracks(self.token()) + .unwrap() + .into_iter() + .filter(|track| track.publisher_id() == publisher_id) + .map(|_track| Arc::new(RemoteTrackPublication {})) + .collect() + } + + pub fn remote_video_tracks(&self, publisher_id: &str) -> Vec> { + if !self.is_connected() { + return Vec::new(); + } + + self.test_server() + .video_tracks(self.token()) + .unwrap() + .into_iter() + .filter(|track| track.publisher_id() == publisher_id) + .collect() + } + + pub fn remote_audio_track_updates(&self) -> impl Stream { + self.0.lock().audio_track_updates.1.clone() + } + + pub fn remote_video_track_updates(&self) -> impl Stream { + self.0.lock().video_track_updates.1.clone() + } + + pub fn set_display_sources(&self, sources: Vec) { + self.0.lock().display_sources = sources; + } + + fn test_server(&self) -> Arc { + match self.0.lock().connection.1.borrow().clone() { + ConnectionState::Disconnected => panic!("must be connected to call this method"), + ConnectionState::Connected { url, .. } => TestServer::get(&url).unwrap(), + } + } + + fn token(&self) -> String { + match self.0.lock().connection.1.borrow().clone() { + ConnectionState::Disconnected => panic!("must be connected to call this method"), + ConnectionState::Connected { token, .. } => token, + } + } + + fn is_connected(&self) -> bool { + match *self.0.lock().connection.1.borrow() { + ConnectionState::Disconnected => false, + ConnectionState::Connected { .. } => true, + } + } +} + +impl Drop for Room { + fn drop(&mut self) { + if let ConnectionState::Connected { token, .. } = mem::replace( + &mut *self.0.lock().connection.0.borrow_mut(), + ConnectionState::Disconnected, + ) { + if let Ok(server) = TestServer::get(&token) { + let executor = server.executor.clone(); + executor + .spawn(async move { server.leave_room(token).await.unwrap() }) + .detach(); + } + } + } +} + +pub struct LocalTrackPublication; + +impl LocalTrackPublication { + pub fn set_mute(&self, _mute: bool) -> impl Future> { + async { Ok(()) } + } +} + +pub struct RemoteTrackPublication; + +impl RemoteTrackPublication { + pub fn set_enabled(&self, _enabled: bool) -> impl Future> { + async { Ok(()) } + } + + pub fn is_muted(&self) -> bool { + false + } + + pub fn sid(&self) -> String { + "".to_string() + } +} + +#[derive(Clone)] +pub struct LocalVideoTrack { + frames_rx: async_broadcast::Receiver, +} + +impl LocalVideoTrack { + pub fn screen_share_for_display(display: &MacOSDisplay) -> Self { + Self { + frames_rx: display.frames.1.clone(), + } + } +} + +#[derive(Clone)] +pub struct LocalAudioTrack; + +impl LocalAudioTrack { + pub fn create() -> Self { + Self + } +} + +#[derive(Debug)] +pub struct RemoteVideoTrack { + sid: Sid, + publisher_id: Sid, + frames_rx: async_broadcast::Receiver, +} + +impl RemoteVideoTrack { + pub fn sid(&self) -> &str { + &self.sid + } + + pub fn publisher_id(&self) -> &str { + &self.publisher_id + } + + pub fn frames(&self) -> async_broadcast::Receiver { + self.frames_rx.clone() + } +} + +#[derive(Debug)] +pub struct RemoteAudioTrack { + sid: Sid, + publisher_id: Sid, +} + +impl RemoteAudioTrack { + pub fn sid(&self) -> &str { + &self.sid + } + + pub fn publisher_id(&self) -> &str { + &self.publisher_id + } + + pub fn enable(&self) -> impl Future> { + async { Ok(()) } + } + + pub fn disable(&self) -> impl Future> { + async { Ok(()) } + } +} + +#[derive(Clone)] +pub enum RemoteVideoTrackUpdate { + Subscribed(Arc), + Unsubscribed { publisher_id: Sid, track_id: Sid }, +} + +#[derive(Clone)] +pub enum RemoteAudioTrackUpdate { + ActiveSpeakersChanged { speakers: Vec }, + MuteChanged { track_id: Sid, muted: bool }, + Subscribed(Arc, Arc), + Unsubscribed { publisher_id: Sid, track_id: Sid }, +} + +#[derive(Clone)] +pub struct MacOSDisplay { + frames: ( + async_broadcast::Sender, + async_broadcast::Receiver, + ), +} + +impl MacOSDisplay { + pub fn new() -> Self { + Self { + frames: async_broadcast::broadcast(128), + } + } + + pub fn send_frame(&self, frame: Frame) { + self.frames.0.try_broadcast(frame).unwrap(); + } +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Frame { + pub label: String, + pub width: usize, + pub height: usize, +} + +impl Frame { + pub fn width(&self) -> usize { + self.width + } + + pub fn height(&self) -> usize { + self.height + } + + pub fn image(&self) -> CVImageBuffer { + unimplemented!("you can't call this in test mode") + } +} diff --git a/crates/multi_buffer2/Cargo.toml b/crates/multi_buffer2/Cargo.toml new file mode 100644 index 0000000000..4c56bab9dc --- /dev/null +++ b/crates/multi_buffer2/Cargo.toml @@ -0,0 +1,78 @@ +[package] +name = "multi_buffer2" +version = "0.1.0" +edition = "2021" +publish = false + +[lib] +path = "src/multi_buffer2.rs" +doctest = false + +[features] +test-support = [ + "copilot2/test-support", + "text/test-support", + "language2/test-support", + "gpui2/test-support", + "util/test-support", + "tree-sitter-rust", + "tree-sitter-typescript" +] + +[dependencies] +client2 = { path = "../client2" } +clock = { path = "../clock" } +collections = { path = "../collections" } +git = { path = "../git" } +gpui2 = { path = "../gpui2" } +language2 = { path = "../language2" } +lsp2 = { path = "../lsp2" } +rich_text = { path = "../rich_text" } +settings2 = { path = "../settings2" } +snippet = { path = "../snippet" } +sum_tree = { path = "../sum_tree" } +text = { path = "../text" } +theme2 = { path = "../theme2" } +util = { path = "../util" } + +aho-corasick = "1.1" +anyhow.workspace = true +convert_case = "0.6.0" +futures.workspace = true +indoc = "1.0.4" +itertools = "0.10" +lazy_static.workspace = true +log.workspace = true +ordered-float.workspace = true +parking_lot.workspace = true +postage.workspace = true +pulldown-cmark = { version = "0.9.2", default-features = false } +rand.workspace = true +schemars.workspace = true +serde.workspace = true +serde_derive.workspace = true +smallvec.workspace = true +smol.workspace = true + +tree-sitter-rust = { workspace = true, optional = true } +tree-sitter-html = { workspace = true, optional = true } +tree-sitter-typescript = { workspace = true, optional = true } + +[dev-dependencies] +copilot2 = { path = "../copilot2", features = ["test-support"] } +text = { path = "../text", features = ["test-support"] } +language2 = { path = "../language2", features = ["test-support"] } +lsp2 = { path = "../lsp2", features = ["test-support"] } +gpui2 = { path = "../gpui2", features = ["test-support"] } +util = { path = "../util", features = ["test-support"] } +project2 = { path = "../project2", features = ["test-support"] } +settings2 = { path = "../settings2", features = ["test-support"] } + +ctor.workspace = true +env_logger.workspace = true +rand.workspace = true +unindent.workspace = true +tree-sitter.workspace = true +tree-sitter-rust.workspace = true +tree-sitter-html.workspace = true +tree-sitter-typescript.workspace = true diff --git a/crates/multi_buffer2/src/anchor.rs b/crates/multi_buffer2/src/anchor.rs new file mode 100644 index 0000000000..fa65bfc800 --- /dev/null +++ b/crates/multi_buffer2/src/anchor.rs @@ -0,0 +1,138 @@ +use super::{ExcerptId, MultiBufferSnapshot, ToOffset, ToOffsetUtf16, ToPoint}; +use language2::{OffsetUtf16, Point, TextDimension}; +use std::{ + cmp::Ordering, + ops::{Range, Sub}, +}; +use sum_tree::Bias; + +#[derive(Clone, Copy, Eq, PartialEq, Debug, Hash)] +pub struct Anchor { + pub buffer_id: Option, + pub excerpt_id: ExcerptId, + pub text_anchor: text::Anchor, +} + +impl Anchor { + pub fn min() -> Self { + Self { + buffer_id: None, + excerpt_id: ExcerptId::min(), + text_anchor: text::Anchor::MIN, + } + } + + pub fn max() -> Self { + Self { + buffer_id: None, + excerpt_id: ExcerptId::max(), + text_anchor: text::Anchor::MAX, + } + } + + pub fn cmp(&self, other: &Anchor, snapshot: &MultiBufferSnapshot) -> Ordering { + let excerpt_id_cmp = self.excerpt_id.cmp(&other.excerpt_id, snapshot); + if excerpt_id_cmp.is_eq() { + if self.excerpt_id == ExcerptId::min() || self.excerpt_id == ExcerptId::max() { + Ordering::Equal + } else if let Some(excerpt) = snapshot.excerpt(self.excerpt_id) { + self.text_anchor.cmp(&other.text_anchor, &excerpt.buffer) + } else { + Ordering::Equal + } + } else { + excerpt_id_cmp + } + } + + pub fn bias(&self) -> Bias { + self.text_anchor.bias + } + + pub fn bias_left(&self, snapshot: &MultiBufferSnapshot) -> Anchor { + if self.text_anchor.bias != Bias::Left { + if let Some(excerpt) = snapshot.excerpt(self.excerpt_id) { + return Self { + buffer_id: self.buffer_id, + excerpt_id: self.excerpt_id.clone(), + text_anchor: self.text_anchor.bias_left(&excerpt.buffer), + }; + } + } + self.clone() + } + + pub fn bias_right(&self, snapshot: &MultiBufferSnapshot) -> Anchor { + if self.text_anchor.bias != Bias::Right { + if let Some(excerpt) = snapshot.excerpt(self.excerpt_id) { + return Self { + buffer_id: self.buffer_id, + excerpt_id: self.excerpt_id.clone(), + text_anchor: self.text_anchor.bias_right(&excerpt.buffer), + }; + } + } + self.clone() + } + + pub fn summary(&self, snapshot: &MultiBufferSnapshot) -> D + where + D: TextDimension + Ord + Sub, + { + snapshot.summary_for_anchor(self) + } + + pub fn is_valid(&self, snapshot: &MultiBufferSnapshot) -> bool { + if *self == Anchor::min() || *self == Anchor::max() { + true + } else if let Some(excerpt) = snapshot.excerpt(self.excerpt_id) { + excerpt.contains(self) + && (self.text_anchor == excerpt.range.context.start + || self.text_anchor == excerpt.range.context.end + || self.text_anchor.is_valid(&excerpt.buffer)) + } else { + false + } + } +} + +impl ToOffset for Anchor { + fn to_offset(&self, snapshot: &MultiBufferSnapshot) -> usize { + self.summary(snapshot) + } +} + +impl ToOffsetUtf16 for Anchor { + fn to_offset_utf16(&self, snapshot: &MultiBufferSnapshot) -> OffsetUtf16 { + self.summary(snapshot) + } +} + +impl ToPoint for Anchor { + fn to_point<'a>(&self, snapshot: &MultiBufferSnapshot) -> Point { + self.summary(snapshot) + } +} + +pub trait AnchorRangeExt { + fn cmp(&self, b: &Range, buffer: &MultiBufferSnapshot) -> Ordering; + fn to_offset(&self, content: &MultiBufferSnapshot) -> Range; + fn to_point(&self, content: &MultiBufferSnapshot) -> Range; +} + +impl AnchorRangeExt for Range { + fn cmp(&self, other: &Range, buffer: &MultiBufferSnapshot) -> Ordering { + match self.start.cmp(&other.start, buffer) { + Ordering::Equal => other.end.cmp(&self.end, buffer), + ord => ord, + } + } + + fn to_offset(&self, content: &MultiBufferSnapshot) -> Range { + self.start.to_offset(content)..self.end.to_offset(content) + } + + fn to_point(&self, content: &MultiBufferSnapshot) -> Range { + self.start.to_point(content)..self.end.to_point(content) + } +} diff --git a/crates/multi_buffer2/src/multi_buffer2.rs b/crates/multi_buffer2/src/multi_buffer2.rs new file mode 100644 index 0000000000..c5827b8b13 --- /dev/null +++ b/crates/multi_buffer2/src/multi_buffer2.rs @@ -0,0 +1,5393 @@ +mod anchor; + +pub use anchor::{Anchor, AnchorRangeExt}; +use anyhow::{anyhow, Result}; +use clock::ReplicaId; +use collections::{BTreeMap, Bound, HashMap, HashSet}; +use futures::{channel::mpsc, SinkExt}; +use git::diff::DiffHunk; +use gpui2::{AppContext, EventEmitter, Model, ModelContext}; +pub use language2::Completion; +use language2::{ + char_kind, + language_settings::{language_settings, LanguageSettings}, + AutoindentMode, Buffer, BufferChunks, BufferSnapshot, CharKind, Chunk, CursorShape, + DiagnosticEntry, File, IndentSize, Language, LanguageScope, OffsetRangeExt, OffsetUtf16, + Outline, OutlineItem, Point, PointUtf16, Selection, TextDimension, ToOffset as _, + ToOffsetUtf16 as _, ToPoint as _, ToPointUtf16 as _, TransactionId, Unclipped, +}; +use std::{ + borrow::Cow, + cell::{Ref, RefCell}, + cmp, fmt, + future::Future, + io, + iter::{self, FromIterator}, + mem, + ops::{Range, RangeBounds, Sub}, + str, + sync::Arc, + time::{Duration, Instant}, +}; +use sum_tree::{Bias, Cursor, SumTree}; +use text::{ + locator::Locator, + subscription::{Subscription, Topic}, + Edit, TextSummary, +}; +use theme2::SyntaxTheme; +use util::post_inc; + +#[cfg(any(test, feature = "test-support"))] +use gpui2::Context; + +const NEWLINES: &[u8] = &[b'\n'; u8::MAX as usize]; + +#[derive(Debug, Default, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub struct ExcerptId(usize); + +pub struct MultiBuffer { + snapshot: RefCell, + buffers: RefCell>, + next_excerpt_id: usize, + subscriptions: Topic, + singleton: bool, + replica_id: ReplicaId, + history: History, + title: Option, +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum Event { + ExcerptsAdded { + buffer: Model, + predecessor: ExcerptId, + excerpts: Vec<(ExcerptId, ExcerptRange)>, + }, + ExcerptsRemoved { + ids: Vec, + }, + ExcerptsEdited { + ids: Vec, + }, + Edited { + sigleton_buffer_edited: bool, + }, + TransactionUndone { + transaction_id: TransactionId, + }, + Reloaded, + DiffBaseChanged, + LanguageChanged, + Reparsed, + Saved, + FileHandleChanged, + Closed, + DirtyChanged, + DiagnosticsUpdated, +} + +#[derive(Clone)] +struct History { + next_transaction_id: TransactionId, + undo_stack: Vec, + redo_stack: Vec, + transaction_depth: usize, + group_interval: Duration, +} + +#[derive(Clone)] +struct Transaction { + id: TransactionId, + buffer_transactions: HashMap, + first_edit_at: Instant, + last_edit_at: Instant, + suppress_grouping: bool, +} + +pub trait ToOffset: 'static + fmt::Debug { + fn to_offset(&self, snapshot: &MultiBufferSnapshot) -> usize; +} + +pub trait ToOffsetUtf16: 'static + fmt::Debug { + fn to_offset_utf16(&self, snapshot: &MultiBufferSnapshot) -> OffsetUtf16; +} + +pub trait ToPoint: 'static + fmt::Debug { + fn to_point(&self, snapshot: &MultiBufferSnapshot) -> Point; +} + +pub trait ToPointUtf16: 'static + fmt::Debug { + fn to_point_utf16(&self, snapshot: &MultiBufferSnapshot) -> PointUtf16; +} + +struct BufferState { + buffer: Model, + last_version: clock::Global, + last_parse_count: usize, + last_selections_update_count: usize, + last_diagnostics_update_count: usize, + last_file_update_count: usize, + last_git_diff_update_count: usize, + excerpts: Vec, + _subscriptions: [gpui2::Subscription; 2], +} + +#[derive(Clone, Default)] +pub struct MultiBufferSnapshot { + singleton: bool, + excerpts: SumTree, + excerpt_ids: SumTree, + parse_count: usize, + diagnostics_update_count: usize, + trailing_excerpt_update_count: usize, + git_diff_update_count: usize, + edit_count: usize, + is_dirty: bool, + has_conflict: bool, +} + +pub struct ExcerptBoundary { + pub id: ExcerptId, + pub row: u32, + pub buffer: BufferSnapshot, + pub range: ExcerptRange, + pub starts_new_buffer: bool, +} + +#[derive(Clone)] +struct Excerpt { + id: ExcerptId, + locator: Locator, + buffer_id: u64, + buffer: BufferSnapshot, + range: ExcerptRange, + max_buffer_row: u32, + text_summary: TextSummary, + has_trailing_newline: bool, +} + +#[derive(Clone, Debug)] +struct ExcerptIdMapping { + id: ExcerptId, + locator: Locator, +} + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct ExcerptRange { + pub context: Range, + pub primary: Option>, +} + +#[derive(Clone, Debug, Default)] +struct ExcerptSummary { + excerpt_id: ExcerptId, + excerpt_locator: Locator, + max_buffer_row: u32, + text: TextSummary, +} + +#[derive(Clone)] +pub struct MultiBufferRows<'a> { + buffer_row_range: Range, + excerpts: Cursor<'a, Excerpt, Point>, +} + +pub struct MultiBufferChunks<'a> { + range: Range, + excerpts: Cursor<'a, Excerpt, usize>, + excerpt_chunks: Option>, + language_aware: bool, +} + +pub struct MultiBufferBytes<'a> { + range: Range, + excerpts: Cursor<'a, Excerpt, usize>, + excerpt_bytes: Option>, + chunk: &'a [u8], +} + +pub struct ReversedMultiBufferBytes<'a> { + range: Range, + excerpts: Cursor<'a, Excerpt, usize>, + excerpt_bytes: Option>, + chunk: &'a [u8], +} + +struct ExcerptChunks<'a> { + content_chunks: BufferChunks<'a>, + footer_height: usize, +} + +struct ExcerptBytes<'a> { + content_bytes: text::Bytes<'a>, + footer_height: usize, +} + +impl MultiBuffer { + pub fn new(replica_id: ReplicaId) -> Self { + Self { + snapshot: Default::default(), + buffers: Default::default(), + next_excerpt_id: 1, + subscriptions: Default::default(), + singleton: false, + replica_id, + history: History { + next_transaction_id: Default::default(), + undo_stack: Default::default(), + redo_stack: Default::default(), + transaction_depth: 0, + group_interval: Duration::from_millis(300), + }, + title: Default::default(), + } + } + + pub fn clone(&self, new_cx: &mut ModelContext) -> Self { + let mut buffers = HashMap::default(); + for (buffer_id, buffer_state) in self.buffers.borrow().iter() { + buffers.insert( + *buffer_id, + BufferState { + buffer: buffer_state.buffer.clone(), + last_version: buffer_state.last_version.clone(), + last_parse_count: buffer_state.last_parse_count, + last_selections_update_count: buffer_state.last_selections_update_count, + last_diagnostics_update_count: buffer_state.last_diagnostics_update_count, + last_file_update_count: buffer_state.last_file_update_count, + last_git_diff_update_count: buffer_state.last_git_diff_update_count, + excerpts: buffer_state.excerpts.clone(), + _subscriptions: [ + new_cx.observe(&buffer_state.buffer, |_, _, cx| cx.notify()), + new_cx.subscribe(&buffer_state.buffer, Self::on_buffer_event), + ], + }, + ); + } + Self { + snapshot: RefCell::new(self.snapshot.borrow().clone()), + buffers: RefCell::new(buffers), + next_excerpt_id: 1, + subscriptions: Default::default(), + singleton: self.singleton, + replica_id: self.replica_id, + history: self.history.clone(), + title: self.title.clone(), + } + } + + pub fn with_title(mut self, title: String) -> Self { + self.title = Some(title); + self + } + + pub fn singleton(buffer: Model, cx: &mut ModelContext) -> Self { + let mut this = Self::new(buffer.read(cx).replica_id()); + this.singleton = true; + this.push_excerpts( + buffer, + [ExcerptRange { + context: text::Anchor::MIN..text::Anchor::MAX, + primary: None, + }], + cx, + ); + this.snapshot.borrow_mut().singleton = true; + this + } + + pub fn replica_id(&self) -> ReplicaId { + self.replica_id + } + + pub fn snapshot(&self, cx: &AppContext) -> MultiBufferSnapshot { + self.sync(cx); + self.snapshot.borrow().clone() + } + + pub fn read(&self, cx: &AppContext) -> Ref { + self.sync(cx); + self.snapshot.borrow() + } + + pub fn as_singleton(&self) -> Option> { + if self.singleton { + return Some( + self.buffers + .borrow() + .values() + .next() + .unwrap() + .buffer + .clone(), + ); + } else { + None + } + } + + pub fn is_singleton(&self) -> bool { + self.singleton + } + + pub fn subscribe(&mut self) -> Subscription { + self.subscriptions.subscribe() + } + + pub fn is_dirty(&self, cx: &AppContext) -> bool { + self.read(cx).is_dirty() + } + + pub fn has_conflict(&self, cx: &AppContext) -> bool { + self.read(cx).has_conflict() + } + + // The `is_empty` signature doesn't match what clippy expects + #[allow(clippy::len_without_is_empty)] + pub fn len(&self, cx: &AppContext) -> usize { + self.read(cx).len() + } + + pub fn is_empty(&self, cx: &AppContext) -> bool { + self.len(cx) != 0 + } + + pub fn symbols_containing( + &self, + offset: T, + theme: Option<&SyntaxTheme>, + cx: &AppContext, + ) -> Option<(u64, Vec>)> { + self.read(cx).symbols_containing(offset, theme) + } + + pub fn edit( + &mut self, + edits: I, + mut autoindent_mode: Option, + cx: &mut ModelContext, + ) where + I: IntoIterator, T)>, + S: ToOffset, + T: Into>, + { + if self.buffers.borrow().is_empty() { + return; + } + + let snapshot = self.read(cx); + let edits = edits.into_iter().map(|(range, new_text)| { + let mut range = range.start.to_offset(&snapshot)..range.end.to_offset(&snapshot); + if range.start > range.end { + mem::swap(&mut range.start, &mut range.end); + } + (range, new_text) + }); + + if let Some(buffer) = self.as_singleton() { + return buffer.update(cx, |buffer, cx| { + buffer.edit(edits, autoindent_mode, cx); + }); + } + + let original_indent_columns = match &mut autoindent_mode { + Some(AutoindentMode::Block { + original_indent_columns, + }) => mem::take(original_indent_columns), + _ => Default::default(), + }; + + struct BufferEdit { + range: Range, + new_text: Arc, + is_insertion: bool, + original_indent_column: u32, + } + let mut buffer_edits: HashMap> = Default::default(); + let mut edited_excerpt_ids = Vec::new(); + let mut cursor = snapshot.excerpts.cursor::(); + for (ix, (range, new_text)) in edits.enumerate() { + let new_text: Arc = new_text.into(); + let original_indent_column = original_indent_columns.get(ix).copied().unwrap_or(0); + cursor.seek(&range.start, Bias::Right, &()); + if cursor.item().is_none() && range.start == *cursor.start() { + cursor.prev(&()); + } + let start_excerpt = cursor.item().expect("start offset out of bounds"); + let start_overshoot = range.start - cursor.start(); + let buffer_start = start_excerpt + .range + .context + .start + .to_offset(&start_excerpt.buffer) + + start_overshoot; + edited_excerpt_ids.push(start_excerpt.id); + + cursor.seek(&range.end, Bias::Right, &()); + if cursor.item().is_none() && range.end == *cursor.start() { + cursor.prev(&()); + } + let end_excerpt = cursor.item().expect("end offset out of bounds"); + let end_overshoot = range.end - cursor.start(); + let buffer_end = end_excerpt + .range + .context + .start + .to_offset(&end_excerpt.buffer) + + end_overshoot; + + if start_excerpt.id == end_excerpt.id { + buffer_edits + .entry(start_excerpt.buffer_id) + .or_insert(Vec::new()) + .push(BufferEdit { + range: buffer_start..buffer_end, + new_text, + is_insertion: true, + original_indent_column, + }); + } else { + edited_excerpt_ids.push(end_excerpt.id); + let start_excerpt_range = buffer_start + ..start_excerpt + .range + .context + .end + .to_offset(&start_excerpt.buffer); + let end_excerpt_range = end_excerpt + .range + .context + .start + .to_offset(&end_excerpt.buffer) + ..buffer_end; + buffer_edits + .entry(start_excerpt.buffer_id) + .or_insert(Vec::new()) + .push(BufferEdit { + range: start_excerpt_range, + new_text: new_text.clone(), + is_insertion: true, + original_indent_column, + }); + buffer_edits + .entry(end_excerpt.buffer_id) + .or_insert(Vec::new()) + .push(BufferEdit { + range: end_excerpt_range, + new_text: new_text.clone(), + is_insertion: false, + original_indent_column, + }); + + cursor.seek(&range.start, Bias::Right, &()); + cursor.next(&()); + while let Some(excerpt) = cursor.item() { + if excerpt.id == end_excerpt.id { + break; + } + buffer_edits + .entry(excerpt.buffer_id) + .or_insert(Vec::new()) + .push(BufferEdit { + range: excerpt.range.context.to_offset(&excerpt.buffer), + new_text: new_text.clone(), + is_insertion: false, + original_indent_column, + }); + edited_excerpt_ids.push(excerpt.id); + cursor.next(&()); + } + } + } + + drop(cursor); + drop(snapshot); + // Non-generic part of edit, hoisted out to avoid blowing up LLVM IR. + fn tail( + this: &mut MultiBuffer, + buffer_edits: HashMap>, + autoindent_mode: Option, + edited_excerpt_ids: Vec, + cx: &mut ModelContext, + ) { + for (buffer_id, mut edits) in buffer_edits { + edits.sort_unstable_by_key(|edit| edit.range.start); + this.buffers.borrow()[&buffer_id] + .buffer + .update(cx, |buffer, cx| { + let mut edits = edits.into_iter().peekable(); + let mut insertions = Vec::new(); + let mut original_indent_columns = Vec::new(); + let mut deletions = Vec::new(); + let empty_str: Arc = "".into(); + while let Some(BufferEdit { + mut range, + new_text, + mut is_insertion, + original_indent_column, + }) = edits.next() + { + while let Some(BufferEdit { + range: next_range, + is_insertion: next_is_insertion, + .. + }) = edits.peek() + { + if range.end >= next_range.start { + range.end = cmp::max(next_range.end, range.end); + is_insertion |= *next_is_insertion; + edits.next(); + } else { + break; + } + } + + if is_insertion { + original_indent_columns.push(original_indent_column); + insertions.push(( + buffer.anchor_before(range.start) + ..buffer.anchor_before(range.end), + new_text.clone(), + )); + } else if !range.is_empty() { + deletions.push(( + buffer.anchor_before(range.start) + ..buffer.anchor_before(range.end), + empty_str.clone(), + )); + } + } + + let deletion_autoindent_mode = + if let Some(AutoindentMode::Block { .. }) = autoindent_mode { + Some(AutoindentMode::Block { + original_indent_columns: Default::default(), + }) + } else { + None + }; + let insertion_autoindent_mode = + if let Some(AutoindentMode::Block { .. }) = autoindent_mode { + Some(AutoindentMode::Block { + original_indent_columns, + }) + } else { + None + }; + + buffer.edit(deletions, deletion_autoindent_mode, cx); + buffer.edit(insertions, insertion_autoindent_mode, cx); + }) + } + + cx.emit(Event::ExcerptsEdited { + ids: edited_excerpt_ids, + }); + } + tail(self, buffer_edits, autoindent_mode, edited_excerpt_ids, cx); + } + + pub fn start_transaction(&mut self, cx: &mut ModelContext) -> Option { + self.start_transaction_at(Instant::now(), cx) + } + + pub fn start_transaction_at( + &mut self, + now: Instant, + cx: &mut ModelContext, + ) -> Option { + if let Some(buffer) = self.as_singleton() { + return buffer.update(cx, |buffer, _| buffer.start_transaction_at(now)); + } + + for BufferState { buffer, .. } in self.buffers.borrow().values() { + buffer.update(cx, |buffer, _| buffer.start_transaction_at(now)); + } + self.history.start_transaction(now) + } + + pub fn end_transaction(&mut self, cx: &mut ModelContext) -> Option { + self.end_transaction_at(Instant::now(), cx) + } + + pub fn end_transaction_at( + &mut self, + now: Instant, + cx: &mut ModelContext, + ) -> Option { + if let Some(buffer) = self.as_singleton() { + return buffer.update(cx, |buffer, cx| buffer.end_transaction_at(now, cx)); + } + + let mut buffer_transactions = HashMap::default(); + for BufferState { buffer, .. } in self.buffers.borrow().values() { + if let Some(transaction_id) = + buffer.update(cx, |buffer, cx| buffer.end_transaction_at(now, cx)) + { + buffer_transactions.insert(buffer.read(cx).remote_id(), transaction_id); + } + } + + if self.history.end_transaction(now, buffer_transactions) { + let transaction_id = self.history.group().unwrap(); + Some(transaction_id) + } else { + None + } + } + + pub fn merge_transactions( + &mut self, + transaction: TransactionId, + destination: TransactionId, + cx: &mut ModelContext, + ) { + if let Some(buffer) = self.as_singleton() { + buffer.update(cx, |buffer, _| { + buffer.merge_transactions(transaction, destination) + }); + } else { + if let Some(transaction) = self.history.forget(transaction) { + if let Some(destination) = self.history.transaction_mut(destination) { + for (buffer_id, buffer_transaction_id) in transaction.buffer_transactions { + if let Some(destination_buffer_transaction_id) = + destination.buffer_transactions.get(&buffer_id) + { + if let Some(state) = self.buffers.borrow().get(&buffer_id) { + state.buffer.update(cx, |buffer, _| { + buffer.merge_transactions( + buffer_transaction_id, + *destination_buffer_transaction_id, + ) + }); + } + } else { + destination + .buffer_transactions + .insert(buffer_id, buffer_transaction_id); + } + } + } + } + } + } + + pub fn finalize_last_transaction(&mut self, cx: &mut ModelContext) { + self.history.finalize_last_transaction(); + for BufferState { buffer, .. } in self.buffers.borrow().values() { + buffer.update(cx, |buffer, _| { + buffer.finalize_last_transaction(); + }); + } + } + + pub fn push_transaction<'a, T>(&mut self, buffer_transactions: T, cx: &mut ModelContext) + where + T: IntoIterator, &'a language2::Transaction)>, + { + self.history + .push_transaction(buffer_transactions, Instant::now(), cx); + self.history.finalize_last_transaction(); + } + + pub fn group_until_transaction( + &mut self, + transaction_id: TransactionId, + cx: &mut ModelContext, + ) { + if let Some(buffer) = self.as_singleton() { + buffer.update(cx, |buffer, _| { + buffer.group_until_transaction(transaction_id) + }); + } else { + self.history.group_until(transaction_id); + } + } + + pub fn set_active_selections( + &mut self, + selections: &[Selection], + line_mode: bool, + cursor_shape: CursorShape, + cx: &mut ModelContext, + ) { + let mut selections_by_buffer: HashMap>> = + Default::default(); + let snapshot = self.read(cx); + let mut cursor = snapshot.excerpts.cursor::>(); + for selection in selections { + let start_locator = snapshot.excerpt_locator_for_id(selection.start.excerpt_id); + let end_locator = snapshot.excerpt_locator_for_id(selection.end.excerpt_id); + + cursor.seek(&Some(start_locator), Bias::Left, &()); + while let Some(excerpt) = cursor.item() { + if excerpt.locator > *end_locator { + break; + } + + let mut start = excerpt.range.context.start; + let mut end = excerpt.range.context.end; + if excerpt.id == selection.start.excerpt_id { + start = selection.start.text_anchor; + } + if excerpt.id == selection.end.excerpt_id { + end = selection.end.text_anchor; + } + selections_by_buffer + .entry(excerpt.buffer_id) + .or_default() + .push(Selection { + id: selection.id, + start, + end, + reversed: selection.reversed, + goal: selection.goal, + }); + + cursor.next(&()); + } + } + + for (buffer_id, buffer_state) in self.buffers.borrow().iter() { + if !selections_by_buffer.contains_key(buffer_id) { + buffer_state + .buffer + .update(cx, |buffer, cx| buffer.remove_active_selections(cx)); + } + } + + for (buffer_id, mut selections) in selections_by_buffer { + self.buffers.borrow()[&buffer_id] + .buffer + .update(cx, |buffer, cx| { + selections.sort_unstable_by(|a, b| a.start.cmp(&b.start, buffer)); + let mut selections = selections.into_iter().peekable(); + let merged_selections = Arc::from_iter(iter::from_fn(|| { + let mut selection = selections.next()?; + while let Some(next_selection) = selections.peek() { + if selection.end.cmp(&next_selection.start, buffer).is_ge() { + let next_selection = selections.next().unwrap(); + if next_selection.end.cmp(&selection.end, buffer).is_ge() { + selection.end = next_selection.end; + } + } else { + break; + } + } + Some(selection) + })); + buffer.set_active_selections(merged_selections, line_mode, cursor_shape, cx); + }); + } + } + + pub fn remove_active_selections(&mut self, cx: &mut ModelContext) { + for buffer in self.buffers.borrow().values() { + buffer + .buffer + .update(cx, |buffer, cx| buffer.remove_active_selections(cx)); + } + } + + pub fn undo(&mut self, cx: &mut ModelContext) -> Option { + let mut transaction_id = None; + if let Some(buffer) = self.as_singleton() { + transaction_id = buffer.update(cx, |buffer, cx| buffer.undo(cx)); + } else { + while let Some(transaction) = self.history.pop_undo() { + let mut undone = false; + for (buffer_id, buffer_transaction_id) in &mut transaction.buffer_transactions { + if let Some(BufferState { buffer, .. }) = self.buffers.borrow().get(buffer_id) { + undone |= buffer.update(cx, |buffer, cx| { + let undo_to = *buffer_transaction_id; + if let Some(entry) = buffer.peek_undo_stack() { + *buffer_transaction_id = entry.transaction_id(); + } + buffer.undo_to_transaction(undo_to, cx) + }); + } + } + + if undone { + transaction_id = Some(transaction.id); + break; + } + } + } + + if let Some(transaction_id) = transaction_id { + cx.emit(Event::TransactionUndone { transaction_id }); + } + + transaction_id + } + + pub fn redo(&mut self, cx: &mut ModelContext) -> Option { + if let Some(buffer) = self.as_singleton() { + return buffer.update(cx, |buffer, cx| buffer.redo(cx)); + } + + while let Some(transaction) = self.history.pop_redo() { + let mut redone = false; + for (buffer_id, buffer_transaction_id) in &mut transaction.buffer_transactions { + if let Some(BufferState { buffer, .. }) = self.buffers.borrow().get(buffer_id) { + redone |= buffer.update(cx, |buffer, cx| { + let redo_to = *buffer_transaction_id; + if let Some(entry) = buffer.peek_redo_stack() { + *buffer_transaction_id = entry.transaction_id(); + } + buffer.redo_to_transaction(redo_to, cx) + }); + } + } + + if redone { + return Some(transaction.id); + } + } + + None + } + + pub fn undo_transaction(&mut self, transaction_id: TransactionId, cx: &mut ModelContext) { + if let Some(buffer) = self.as_singleton() { + buffer.update(cx, |buffer, cx| buffer.undo_transaction(transaction_id, cx)); + } else if let Some(transaction) = self.history.remove_from_undo(transaction_id) { + for (buffer_id, transaction_id) in &transaction.buffer_transactions { + if let Some(BufferState { buffer, .. }) = self.buffers.borrow().get(buffer_id) { + buffer.update(cx, |buffer, cx| { + buffer.undo_transaction(*transaction_id, cx) + }); + } + } + } + } + + pub fn stream_excerpts_with_context_lines( + &mut self, + buffer: Model, + ranges: Vec>, + context_line_count: u32, + cx: &mut ModelContext, + ) -> mpsc::Receiver> { + let (buffer_id, buffer_snapshot) = + buffer.update(cx, |buffer, _| (buffer.remote_id(), buffer.snapshot())); + + let (mut tx, rx) = mpsc::channel(256); + cx.spawn(move |this, mut cx| async move { + let mut excerpt_ranges = Vec::new(); + let mut range_counts = Vec::new(); + cx.executor() + .scoped(|scope| { + scope.spawn(async { + let (ranges, counts) = + build_excerpt_ranges(&buffer_snapshot, &ranges, context_line_count); + excerpt_ranges = ranges; + range_counts = counts; + }); + }) + .await; + + let mut ranges = ranges.into_iter(); + let mut range_counts = range_counts.into_iter(); + for excerpt_ranges in excerpt_ranges.chunks(100) { + let excerpt_ids = match this.update(&mut cx, |this, cx| { + this.push_excerpts(buffer.clone(), excerpt_ranges.iter().cloned(), cx) + }) { + Ok(excerpt_ids) => excerpt_ids, + Err(_) => return, + }; + + for (excerpt_id, range_count) in excerpt_ids.into_iter().zip(range_counts.by_ref()) + { + for range in ranges.by_ref().take(range_count) { + let start = Anchor { + buffer_id: Some(buffer_id), + excerpt_id: excerpt_id.clone(), + text_anchor: range.start, + }; + let end = Anchor { + buffer_id: Some(buffer_id), + excerpt_id: excerpt_id.clone(), + text_anchor: range.end, + }; + if tx.send(start..end).await.is_err() { + break; + } + } + } + } + }) + .detach(); + + rx + } + + pub fn push_excerpts( + &mut self, + buffer: Model, + ranges: impl IntoIterator>, + cx: &mut ModelContext, + ) -> Vec + where + O: text::ToOffset, + { + self.insert_excerpts_after(ExcerptId::max(), buffer, ranges, cx) + } + + pub fn push_excerpts_with_context_lines( + &mut self, + buffer: Model, + ranges: Vec>, + context_line_count: u32, + cx: &mut ModelContext, + ) -> Vec> + where + O: text::ToPoint + text::ToOffset, + { + let buffer_id = buffer.read(cx).remote_id(); + let buffer_snapshot = buffer.read(cx).snapshot(); + let (excerpt_ranges, range_counts) = + build_excerpt_ranges(&buffer_snapshot, &ranges, context_line_count); + + let excerpt_ids = self.push_excerpts(buffer, excerpt_ranges, cx); + + let mut anchor_ranges = Vec::new(); + let mut ranges = ranges.into_iter(); + for (excerpt_id, range_count) in excerpt_ids.into_iter().zip(range_counts.into_iter()) { + anchor_ranges.extend(ranges.by_ref().take(range_count).map(|range| { + let start = Anchor { + buffer_id: Some(buffer_id), + excerpt_id: excerpt_id.clone(), + text_anchor: buffer_snapshot.anchor_after(range.start), + }; + let end = Anchor { + buffer_id: Some(buffer_id), + excerpt_id: excerpt_id.clone(), + text_anchor: buffer_snapshot.anchor_after(range.end), + }; + start..end + })) + } + anchor_ranges + } + + pub fn insert_excerpts_after( + &mut self, + prev_excerpt_id: ExcerptId, + buffer: Model, + ranges: impl IntoIterator>, + cx: &mut ModelContext, + ) -> Vec + where + O: text::ToOffset, + { + let mut ids = Vec::new(); + let mut next_excerpt_id = self.next_excerpt_id; + self.insert_excerpts_with_ids_after( + prev_excerpt_id, + buffer, + ranges.into_iter().map(|range| { + let id = ExcerptId(post_inc(&mut next_excerpt_id)); + ids.push(id); + (id, range) + }), + cx, + ); + ids + } + + pub fn insert_excerpts_with_ids_after( + &mut self, + prev_excerpt_id: ExcerptId, + buffer: Model, + ranges: impl IntoIterator)>, + cx: &mut ModelContext, + ) where + O: text::ToOffset, + { + assert_eq!(self.history.transaction_depth, 0); + let mut ranges = ranges.into_iter().peekable(); + if ranges.peek().is_none() { + return Default::default(); + } + + self.sync(cx); + + let buffer_id = buffer.read(cx).remote_id(); + let buffer_snapshot = buffer.read(cx).snapshot(); + + let mut buffers = self.buffers.borrow_mut(); + let buffer_state = buffers.entry(buffer_id).or_insert_with(|| BufferState { + last_version: buffer_snapshot.version().clone(), + last_parse_count: buffer_snapshot.parse_count(), + last_selections_update_count: buffer_snapshot.selections_update_count(), + last_diagnostics_update_count: buffer_snapshot.diagnostics_update_count(), + last_file_update_count: buffer_snapshot.file_update_count(), + last_git_diff_update_count: buffer_snapshot.git_diff_update_count(), + excerpts: Default::default(), + _subscriptions: [ + cx.observe(&buffer, |_, _, cx| cx.notify()), + cx.subscribe(&buffer, Self::on_buffer_event), + ], + buffer: buffer.clone(), + }); + + let mut snapshot = self.snapshot.borrow_mut(); + + let mut prev_locator = snapshot.excerpt_locator_for_id(prev_excerpt_id).clone(); + let mut new_excerpt_ids = mem::take(&mut snapshot.excerpt_ids); + let mut cursor = snapshot.excerpts.cursor::>(); + let mut new_excerpts = cursor.slice(&prev_locator, Bias::Right, &()); + prev_locator = cursor.start().unwrap_or(Locator::min_ref()).clone(); + + let edit_start = new_excerpts.summary().text.len; + new_excerpts.update_last( + |excerpt| { + excerpt.has_trailing_newline = true; + }, + &(), + ); + + let next_locator = if let Some(excerpt) = cursor.item() { + excerpt.locator.clone() + } else { + Locator::max() + }; + + let mut excerpts = Vec::new(); + while let Some((id, range)) = ranges.next() { + let locator = Locator::between(&prev_locator, &next_locator); + if let Err(ix) = buffer_state.excerpts.binary_search(&locator) { + buffer_state.excerpts.insert(ix, locator.clone()); + } + let range = ExcerptRange { + context: buffer_snapshot.anchor_before(&range.context.start) + ..buffer_snapshot.anchor_after(&range.context.end), + primary: range.primary.map(|primary| { + buffer_snapshot.anchor_before(&primary.start) + ..buffer_snapshot.anchor_after(&primary.end) + }), + }; + if id.0 >= self.next_excerpt_id { + self.next_excerpt_id = id.0 + 1; + } + excerpts.push((id, range.clone())); + let excerpt = Excerpt::new( + id, + locator.clone(), + buffer_id, + buffer_snapshot.clone(), + range, + ranges.peek().is_some() || cursor.item().is_some(), + ); + new_excerpts.push(excerpt, &()); + prev_locator = locator.clone(); + new_excerpt_ids.push(ExcerptIdMapping { id, locator }, &()); + } + + let edit_end = new_excerpts.summary().text.len; + + let suffix = cursor.suffix(&()); + let changed_trailing_excerpt = suffix.is_empty(); + new_excerpts.append(suffix, &()); + drop(cursor); + snapshot.excerpts = new_excerpts; + snapshot.excerpt_ids = new_excerpt_ids; + if changed_trailing_excerpt { + snapshot.trailing_excerpt_update_count += 1; + } + + self.subscriptions.publish_mut([Edit { + old: edit_start..edit_start, + new: edit_start..edit_end, + }]); + cx.emit(Event::Edited { + sigleton_buffer_edited: false, + }); + cx.emit(Event::ExcerptsAdded { + buffer, + predecessor: prev_excerpt_id, + excerpts, + }); + cx.notify(); + } + + pub fn clear(&mut self, cx: &mut ModelContext) { + self.sync(cx); + let ids = self.excerpt_ids(); + self.buffers.borrow_mut().clear(); + let mut snapshot = self.snapshot.borrow_mut(); + let prev_len = snapshot.len(); + snapshot.excerpts = Default::default(); + snapshot.trailing_excerpt_update_count += 1; + snapshot.is_dirty = false; + snapshot.has_conflict = false; + + self.subscriptions.publish_mut([Edit { + old: 0..prev_len, + new: 0..0, + }]); + cx.emit(Event::Edited { + sigleton_buffer_edited: false, + }); + cx.emit(Event::ExcerptsRemoved { ids }); + cx.notify(); + } + + pub fn excerpts_for_buffer( + &self, + buffer: &Model, + cx: &AppContext, + ) -> Vec<(ExcerptId, ExcerptRange)> { + let mut excerpts = Vec::new(); + let snapshot = self.read(cx); + let buffers = self.buffers.borrow(); + let mut cursor = snapshot.excerpts.cursor::>(); + for locator in buffers + .get(&buffer.read(cx).remote_id()) + .map(|state| &state.excerpts) + .into_iter() + .flatten() + { + cursor.seek_forward(&Some(locator), Bias::Left, &()); + if let Some(excerpt) = cursor.item() { + if excerpt.locator == *locator { + excerpts.push((excerpt.id.clone(), excerpt.range.clone())); + } + } + } + + excerpts + } + + pub fn excerpt_ids(&self) -> Vec { + self.snapshot + .borrow() + .excerpts + .iter() + .map(|entry| entry.id) + .collect() + } + + pub fn excerpt_containing( + &self, + position: impl ToOffset, + cx: &AppContext, + ) -> Option<(ExcerptId, Model, Range)> { + let snapshot = self.read(cx); + let position = position.to_offset(&snapshot); + + let mut cursor = snapshot.excerpts.cursor::(); + cursor.seek(&position, Bias::Right, &()); + cursor + .item() + .or_else(|| snapshot.excerpts.last()) + .map(|excerpt| { + ( + excerpt.id.clone(), + self.buffers + .borrow() + .get(&excerpt.buffer_id) + .unwrap() + .buffer + .clone(), + excerpt.range.context.clone(), + ) + }) + } + + // If point is at the end of the buffer, the last excerpt is returned + pub fn point_to_buffer_offset( + &self, + point: T, + cx: &AppContext, + ) -> Option<(Model, usize, ExcerptId)> { + let snapshot = self.read(cx); + let offset = point.to_offset(&snapshot); + let mut cursor = snapshot.excerpts.cursor::(); + cursor.seek(&offset, Bias::Right, &()); + if cursor.item().is_none() { + cursor.prev(&()); + } + + cursor.item().map(|excerpt| { + let excerpt_start = excerpt.range.context.start.to_offset(&excerpt.buffer); + let buffer_point = excerpt_start + offset - *cursor.start(); + let buffer = self.buffers.borrow()[&excerpt.buffer_id].buffer.clone(); + + (buffer, buffer_point, excerpt.id) + }) + } + + pub fn range_to_buffer_ranges( + &self, + range: Range, + cx: &AppContext, + ) -> Vec<(Model, Range, ExcerptId)> { + let snapshot = self.read(cx); + let start = range.start.to_offset(&snapshot); + let end = range.end.to_offset(&snapshot); + + let mut result = Vec::new(); + let mut cursor = snapshot.excerpts.cursor::(); + cursor.seek(&start, Bias::Right, &()); + if cursor.item().is_none() { + cursor.prev(&()); + } + + while let Some(excerpt) = cursor.item() { + if *cursor.start() > end { + break; + } + + let mut end_before_newline = cursor.end(&()); + if excerpt.has_trailing_newline { + end_before_newline -= 1; + } + let excerpt_start = excerpt.range.context.start.to_offset(&excerpt.buffer); + let start = excerpt_start + (cmp::max(start, *cursor.start()) - *cursor.start()); + let end = excerpt_start + (cmp::min(end, end_before_newline) - *cursor.start()); + let buffer = self.buffers.borrow()[&excerpt.buffer_id].buffer.clone(); + result.push((buffer, start..end, excerpt.id)); + cursor.next(&()); + } + + result + } + + pub fn remove_excerpts( + &mut self, + excerpt_ids: impl IntoIterator, + cx: &mut ModelContext, + ) { + self.sync(cx); + let ids = excerpt_ids.into_iter().collect::>(); + if ids.is_empty() { + return; + } + + let mut buffers = self.buffers.borrow_mut(); + let mut snapshot = self.snapshot.borrow_mut(); + let mut new_excerpts = SumTree::new(); + let mut cursor = snapshot.excerpts.cursor::<(Option<&Locator>, usize)>(); + let mut edits = Vec::new(); + let mut excerpt_ids = ids.iter().copied().peekable(); + + while let Some(excerpt_id) = excerpt_ids.next() { + // Seek to the next excerpt to remove, preserving any preceding excerpts. + let locator = snapshot.excerpt_locator_for_id(excerpt_id); + new_excerpts.append(cursor.slice(&Some(locator), Bias::Left, &()), &()); + + if let Some(mut excerpt) = cursor.item() { + if excerpt.id != excerpt_id { + continue; + } + let mut old_start = cursor.start().1; + + // Skip over the removed excerpt. + 'remove_excerpts: loop { + if let Some(buffer_state) = buffers.get_mut(&excerpt.buffer_id) { + buffer_state.excerpts.retain(|l| l != &excerpt.locator); + if buffer_state.excerpts.is_empty() { + buffers.remove(&excerpt.buffer_id); + } + } + cursor.next(&()); + + // Skip over any subsequent excerpts that are also removed. + while let Some(&next_excerpt_id) = excerpt_ids.peek() { + let next_locator = snapshot.excerpt_locator_for_id(next_excerpt_id); + if let Some(next_excerpt) = cursor.item() { + if next_excerpt.locator == *next_locator { + excerpt_ids.next(); + excerpt = next_excerpt; + continue 'remove_excerpts; + } + } + break; + } + + break; + } + + // When removing the last excerpt, remove the trailing newline from + // the previous excerpt. + if cursor.item().is_none() && old_start > 0 { + old_start -= 1; + new_excerpts.update_last(|e| e.has_trailing_newline = false, &()); + } + + // Push an edit for the removal of this run of excerpts. + let old_end = cursor.start().1; + let new_start = new_excerpts.summary().text.len; + edits.push(Edit { + old: old_start..old_end, + new: new_start..new_start, + }); + } + } + let suffix = cursor.suffix(&()); + let changed_trailing_excerpt = suffix.is_empty(); + new_excerpts.append(suffix, &()); + drop(cursor); + snapshot.excerpts = new_excerpts; + + if changed_trailing_excerpt { + snapshot.trailing_excerpt_update_count += 1; + } + + self.subscriptions.publish_mut(edits); + cx.emit(Event::Edited { + sigleton_buffer_edited: false, + }); + cx.emit(Event::ExcerptsRemoved { ids }); + cx.notify(); + } + + pub fn wait_for_anchors<'a>( + &self, + anchors: impl 'a + Iterator, + cx: &mut ModelContext, + ) -> impl 'static + Future> { + let borrow = self.buffers.borrow(); + let mut error = None; + let mut futures = Vec::new(); + for anchor in anchors { + if let Some(buffer_id) = anchor.buffer_id { + if let Some(buffer) = borrow.get(&buffer_id) { + buffer.buffer.update(cx, |buffer, _| { + futures.push(buffer.wait_for_anchors([anchor.text_anchor])) + }); + } else { + error = Some(anyhow!( + "buffer {buffer_id} is not part of this multi-buffer" + )); + break; + } + } + } + async move { + if let Some(error) = error { + Err(error)?; + } + for future in futures { + future.await?; + } + Ok(()) + } + } + + pub fn text_anchor_for_position( + &self, + position: T, + cx: &AppContext, + ) -> Option<(Model, language2::Anchor)> { + let snapshot = self.read(cx); + let anchor = snapshot.anchor_before(position); + let buffer = self + .buffers + .borrow() + .get(&anchor.buffer_id?)? + .buffer + .clone(); + Some((buffer, anchor.text_anchor)) + } + + fn on_buffer_event( + &mut self, + _: Model, + event: &language2::Event, + cx: &mut ModelContext, + ) { + cx.emit(match event { + language2::Event::Edited => Event::Edited { + sigleton_buffer_edited: true, + }, + language2::Event::DirtyChanged => Event::DirtyChanged, + language2::Event::Saved => Event::Saved, + language2::Event::FileHandleChanged => Event::FileHandleChanged, + language2::Event::Reloaded => Event::Reloaded, + language2::Event::DiffBaseChanged => Event::DiffBaseChanged, + language2::Event::LanguageChanged => Event::LanguageChanged, + language2::Event::Reparsed => Event::Reparsed, + language2::Event::DiagnosticsUpdated => Event::DiagnosticsUpdated, + language2::Event::Closed => Event::Closed, + + // + language2::Event::Operation(_) => return, + }); + } + + pub fn all_buffers(&self) -> HashSet> { + self.buffers + .borrow() + .values() + .map(|state| state.buffer.clone()) + .collect() + } + + pub fn buffer(&self, buffer_id: u64) -> Option> { + self.buffers + .borrow() + .get(&buffer_id) + .map(|state| state.buffer.clone()) + } + + pub fn is_completion_trigger(&self, position: Anchor, text: &str, cx: &AppContext) -> bool { + let mut chars = text.chars(); + let char = if let Some(char) = chars.next() { + char + } else { + return false; + }; + if chars.next().is_some() { + return false; + } + + let snapshot = self.snapshot(cx); + let position = position.to_offset(&snapshot); + let scope = snapshot.language_scope_at(position); + if char_kind(&scope, char) == CharKind::Word { + return true; + } + + let anchor = snapshot.anchor_before(position); + anchor + .buffer_id + .and_then(|buffer_id| { + let buffer = self.buffers.borrow().get(&buffer_id)?.buffer.clone(); + Some( + buffer + .read(cx) + .completion_triggers() + .iter() + .any(|string| string == text), + ) + }) + .unwrap_or(false) + } + + pub fn language_at<'a, T: ToOffset>( + &self, + point: T, + cx: &'a AppContext, + ) -> Option> { + self.point_to_buffer_offset(point, cx) + .and_then(|(buffer, offset, _)| buffer.read(cx).language_at(offset)) + } + + pub fn settings_at<'a, T: ToOffset>( + &self, + point: T, + cx: &'a AppContext, + ) -> &'a LanguageSettings { + let mut language = None; + let mut file = None; + if let Some((buffer, offset, _)) = self.point_to_buffer_offset(point, cx) { + let buffer = buffer.read(cx); + language = buffer.language_at(offset); + file = buffer.file(); + } + language_settings(language.as_ref(), file, cx) + } + + pub fn for_each_buffer(&self, mut f: impl FnMut(&Model)) { + self.buffers + .borrow() + .values() + .for_each(|state| f(&state.buffer)) + } + + pub fn title<'a>(&'a self, cx: &'a AppContext) -> Cow<'a, str> { + if let Some(title) = self.title.as_ref() { + return title.into(); + } + + if let Some(buffer) = self.as_singleton() { + if let Some(file) = buffer.read(cx).file() { + return file.file_name(cx).to_string_lossy(); + } + } + + "untitled".into() + } + + #[cfg(any(test, feature = "test-support"))] + pub fn is_parsing(&self, cx: &AppContext) -> bool { + self.as_singleton().unwrap().read(cx).is_parsing() + } + + fn sync(&self, cx: &AppContext) { + let mut snapshot = self.snapshot.borrow_mut(); + let mut excerpts_to_edit = Vec::new(); + let mut reparsed = false; + let mut diagnostics_updated = false; + let mut git_diff_updated = false; + let mut is_dirty = false; + let mut has_conflict = false; + let mut edited = false; + let mut buffers = self.buffers.borrow_mut(); + for buffer_state in buffers.values_mut() { + let buffer = buffer_state.buffer.read(cx); + let version = buffer.version(); + let parse_count = buffer.parse_count(); + let selections_update_count = buffer.selections_update_count(); + let diagnostics_update_count = buffer.diagnostics_update_count(); + let file_update_count = buffer.file_update_count(); + let git_diff_update_count = buffer.git_diff_update_count(); + + let buffer_edited = version.changed_since(&buffer_state.last_version); + let buffer_reparsed = parse_count > buffer_state.last_parse_count; + let buffer_selections_updated = + selections_update_count > buffer_state.last_selections_update_count; + let buffer_diagnostics_updated = + diagnostics_update_count > buffer_state.last_diagnostics_update_count; + let buffer_file_updated = file_update_count > buffer_state.last_file_update_count; + let buffer_git_diff_updated = + git_diff_update_count > buffer_state.last_git_diff_update_count; + if buffer_edited + || buffer_reparsed + || buffer_selections_updated + || buffer_diagnostics_updated + || buffer_file_updated + || buffer_git_diff_updated + { + buffer_state.last_version = version; + buffer_state.last_parse_count = parse_count; + buffer_state.last_selections_update_count = selections_update_count; + buffer_state.last_diagnostics_update_count = diagnostics_update_count; + buffer_state.last_file_update_count = file_update_count; + buffer_state.last_git_diff_update_count = git_diff_update_count; + excerpts_to_edit.extend( + buffer_state + .excerpts + .iter() + .map(|locator| (locator, buffer_state.buffer.clone(), buffer_edited)), + ); + } + + edited |= buffer_edited; + reparsed |= buffer_reparsed; + diagnostics_updated |= buffer_diagnostics_updated; + git_diff_updated |= buffer_git_diff_updated; + is_dirty |= buffer.is_dirty(); + has_conflict |= buffer.has_conflict(); + } + if edited { + snapshot.edit_count += 1; + } + if reparsed { + snapshot.parse_count += 1; + } + if diagnostics_updated { + snapshot.diagnostics_update_count += 1; + } + if git_diff_updated { + snapshot.git_diff_update_count += 1; + } + snapshot.is_dirty = is_dirty; + snapshot.has_conflict = has_conflict; + + excerpts_to_edit.sort_unstable_by_key(|(locator, _, _)| *locator); + + let mut edits = Vec::new(); + let mut new_excerpts = SumTree::new(); + let mut cursor = snapshot.excerpts.cursor::<(Option<&Locator>, usize)>(); + + for (locator, buffer, buffer_edited) in excerpts_to_edit { + new_excerpts.append(cursor.slice(&Some(locator), Bias::Left, &()), &()); + let old_excerpt = cursor.item().unwrap(); + let buffer = buffer.read(cx); + let buffer_id = buffer.remote_id(); + + let mut new_excerpt; + if buffer_edited { + edits.extend( + buffer + .edits_since_in_range::( + old_excerpt.buffer.version(), + old_excerpt.range.context.clone(), + ) + .map(|mut edit| { + let excerpt_old_start = cursor.start().1; + let excerpt_new_start = new_excerpts.summary().text.len; + edit.old.start += excerpt_old_start; + edit.old.end += excerpt_old_start; + edit.new.start += excerpt_new_start; + edit.new.end += excerpt_new_start; + edit + }), + ); + + new_excerpt = Excerpt::new( + old_excerpt.id, + locator.clone(), + buffer_id, + buffer.snapshot(), + old_excerpt.range.clone(), + old_excerpt.has_trailing_newline, + ); + } else { + new_excerpt = old_excerpt.clone(); + new_excerpt.buffer = buffer.snapshot(); + } + + new_excerpts.push(new_excerpt, &()); + cursor.next(&()); + } + new_excerpts.append(cursor.suffix(&()), &()); + + drop(cursor); + snapshot.excerpts = new_excerpts; + + self.subscriptions.publish(edits); + } +} + +#[cfg(any(test, feature = "test-support"))] +impl MultiBuffer { + pub fn build_simple(text: &str, cx: &mut gpui2::AppContext) -> Model { + let buffer = cx.build_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), text)); + cx.build_model(|cx| Self::singleton(buffer, cx)) + } + + pub fn build_multi( + excerpts: [(&str, Vec>); COUNT], + cx: &mut gpui2::AppContext, + ) -> Model { + let multi = cx.build_model(|_| Self::new(0)); + for (text, ranges) in excerpts { + let buffer = cx.build_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), text)); + let excerpt_ranges = ranges.into_iter().map(|range| ExcerptRange { + context: range, + primary: None, + }); + multi.update(cx, |multi, cx| { + multi.push_excerpts(buffer, excerpt_ranges, cx) + }); + } + + multi + } + + pub fn build_from_buffer(buffer: Model, cx: &mut gpui2::AppContext) -> Model { + cx.build_model(|cx| Self::singleton(buffer, cx)) + } + + pub fn build_random(rng: &mut impl rand::Rng, cx: &mut gpui2::AppContext) -> Model { + cx.build_model(|cx| { + let mut multibuffer = MultiBuffer::new(0); + let mutation_count = rng.gen_range(1..=5); + multibuffer.randomly_edit_excerpts(rng, mutation_count, cx); + multibuffer + }) + } + + pub fn randomly_edit( + &mut self, + rng: &mut impl rand::Rng, + edit_count: usize, + cx: &mut ModelContext, + ) { + use util::RandomCharIter; + + let snapshot = self.read(cx); + let mut edits: Vec<(Range, Arc)> = Vec::new(); + let mut last_end = None; + for _ in 0..edit_count { + if last_end.map_or(false, |last_end| last_end >= snapshot.len()) { + break; + } + + let new_start = last_end.map_or(0, |last_end| last_end + 1); + let end = snapshot.clip_offset(rng.gen_range(new_start..=snapshot.len()), Bias::Right); + let start = snapshot.clip_offset(rng.gen_range(new_start..=end), Bias::Right); + last_end = Some(end); + + let mut range = start..end; + if rng.gen_bool(0.2) { + mem::swap(&mut range.start, &mut range.end); + } + + let new_text_len = rng.gen_range(0..10); + let new_text: String = RandomCharIter::new(&mut *rng).take(new_text_len).collect(); + + edits.push((range, new_text.into())); + } + log::info!("mutating multi-buffer with {:?}", edits); + drop(snapshot); + + self.edit(edits, None, cx); + } + + pub fn randomly_edit_excerpts( + &mut self, + rng: &mut impl rand::Rng, + mutation_count: usize, + cx: &mut ModelContext, + ) { + use rand::prelude::*; + use std::env; + use util::RandomCharIter; + + let max_excerpts = env::var("MAX_EXCERPTS") + .map(|i| i.parse().expect("invalid `MAX_EXCERPTS` variable")) + .unwrap_or(5); + + let mut buffers = Vec::new(); + for _ in 0..mutation_count { + if rng.gen_bool(0.05) { + log::info!("Clearing multi-buffer"); + self.clear(cx); + continue; + } + + let excerpt_ids = self.excerpt_ids(); + if excerpt_ids.is_empty() || (rng.gen() && excerpt_ids.len() < max_excerpts) { + let buffer_handle = if rng.gen() || self.buffers.borrow().is_empty() { + let text = RandomCharIter::new(&mut *rng).take(10).collect::(); + buffers + .push(cx.build_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), text))); + let buffer = buffers.last().unwrap().read(cx); + log::info!( + "Creating new buffer {} with text: {:?}", + buffer.remote_id(), + buffer.text() + ); + buffers.last().unwrap().clone() + } else { + self.buffers + .borrow() + .values() + .choose(rng) + .unwrap() + .buffer + .clone() + }; + + let buffer = buffer_handle.read(cx); + let buffer_text = buffer.text(); + let ranges = (0..rng.gen_range(0..5)) + .map(|_| { + let end_ix = + buffer.clip_offset(rng.gen_range(0..=buffer.len()), Bias::Right); + let start_ix = buffer.clip_offset(rng.gen_range(0..=end_ix), Bias::Left); + ExcerptRange { + context: start_ix..end_ix, + primary: None, + } + }) + .collect::>(); + log::info!( + "Inserting excerpts from buffer {} and ranges {:?}: {:?}", + buffer_handle.read(cx).remote_id(), + ranges.iter().map(|r| &r.context).collect::>(), + ranges + .iter() + .map(|r| &buffer_text[r.context.clone()]) + .collect::>() + ); + + let excerpt_id = self.push_excerpts(buffer_handle.clone(), ranges, cx); + log::info!("Inserted with ids: {:?}", excerpt_id); + } else { + let remove_count = rng.gen_range(1..=excerpt_ids.len()); + let mut excerpts_to_remove = excerpt_ids + .choose_multiple(rng, remove_count) + .cloned() + .collect::>(); + let snapshot = self.snapshot.borrow(); + excerpts_to_remove.sort_unstable_by(|a, b| a.cmp(b, &*snapshot)); + drop(snapshot); + log::info!("Removing excerpts {:?}", excerpts_to_remove); + self.remove_excerpts(excerpts_to_remove, cx); + } + } + } + + pub fn randomly_mutate( + &mut self, + rng: &mut impl rand::Rng, + mutation_count: usize, + cx: &mut ModelContext, + ) { + use rand::prelude::*; + + if rng.gen_bool(0.7) || self.singleton { + let buffer = self + .buffers + .borrow() + .values() + .choose(rng) + .map(|state| state.buffer.clone()); + + if let Some(buffer) = buffer { + buffer.update(cx, |buffer, cx| { + if rng.gen() { + buffer.randomly_edit(rng, mutation_count, cx); + } else { + buffer.randomly_undo_redo(rng, cx); + } + }); + } else { + self.randomly_edit(rng, mutation_count, cx); + } + } else { + self.randomly_edit_excerpts(rng, mutation_count, cx); + } + + self.check_invariants(cx); + } + + fn check_invariants(&self, cx: &mut ModelContext) { + let snapshot = self.read(cx); + let excerpts = snapshot.excerpts.items(&()); + let excerpt_ids = snapshot.excerpt_ids.items(&()); + + for (ix, excerpt) in excerpts.iter().enumerate() { + if ix == 0 { + if excerpt.locator <= Locator::min() { + panic!("invalid first excerpt locator {:?}", excerpt.locator); + } + } else { + if excerpt.locator <= excerpts[ix - 1].locator { + panic!("excerpts are out-of-order: {:?}", excerpts); + } + } + } + + for (ix, entry) in excerpt_ids.iter().enumerate() { + if ix == 0 { + if entry.id.cmp(&ExcerptId::min(), &*snapshot).is_le() { + panic!("invalid first excerpt id {:?}", entry.id); + } + } else { + if entry.id <= excerpt_ids[ix - 1].id { + panic!("excerpt ids are out-of-order: {:?}", excerpt_ids); + } + } + } + } +} + +impl EventEmitter for MultiBuffer { + type Event = Event; +} + +impl MultiBufferSnapshot { + pub fn text(&self) -> String { + self.chunks(0..self.len(), false) + .map(|chunk| chunk.text) + .collect() + } + + pub fn reversed_chars_at(&self, position: T) -> impl Iterator + '_ { + let mut offset = position.to_offset(self); + let mut cursor = self.excerpts.cursor::(); + cursor.seek(&offset, Bias::Left, &()); + let mut excerpt_chunks = cursor.item().map(|excerpt| { + let end_before_footer = cursor.start() + excerpt.text_summary.len; + let start = excerpt.range.context.start.to_offset(&excerpt.buffer); + let end = start + (cmp::min(offset, end_before_footer) - cursor.start()); + excerpt.buffer.reversed_chunks_in_range(start..end) + }); + iter::from_fn(move || { + if offset == *cursor.start() { + cursor.prev(&()); + let excerpt = cursor.item()?; + excerpt_chunks = Some( + excerpt + .buffer + .reversed_chunks_in_range(excerpt.range.context.clone()), + ); + } + + let excerpt = cursor.item().unwrap(); + if offset == cursor.end(&()) && excerpt.has_trailing_newline { + offset -= 1; + Some("\n") + } else { + let chunk = excerpt_chunks.as_mut().unwrap().next().unwrap(); + offset -= chunk.len(); + Some(chunk) + } + }) + .flat_map(|c| c.chars().rev()) + } + + pub fn chars_at(&self, position: T) -> impl Iterator + '_ { + let offset = position.to_offset(self); + self.text_for_range(offset..self.len()) + .flat_map(|chunk| chunk.chars()) + } + + pub fn text_for_range(&self, range: Range) -> impl Iterator + '_ { + self.chunks(range, false).map(|chunk| chunk.text) + } + + pub fn is_line_blank(&self, row: u32) -> bool { + self.text_for_range(Point::new(row, 0)..Point::new(row, self.line_len(row))) + .all(|chunk| chunk.matches(|c: char| !c.is_whitespace()).next().is_none()) + } + + pub fn contains_str_at(&self, position: T, needle: &str) -> bool + where + T: ToOffset, + { + let position = position.to_offset(self); + position == self.clip_offset(position, Bias::Left) + && self + .bytes_in_range(position..self.len()) + .flatten() + .copied() + .take(needle.len()) + .eq(needle.bytes()) + } + + pub fn surrounding_word(&self, start: T) -> (Range, Option) { + let mut start = start.to_offset(self); + let mut end = start; + let mut next_chars = self.chars_at(start).peekable(); + let mut prev_chars = self.reversed_chars_at(start).peekable(); + + let scope = self.language_scope_at(start); + let kind = |c| char_kind(&scope, c); + let word_kind = cmp::max( + prev_chars.peek().copied().map(kind), + next_chars.peek().copied().map(kind), + ); + + for ch in prev_chars { + if Some(kind(ch)) == word_kind && ch != '\n' { + start -= ch.len_utf8(); + } else { + break; + } + } + + for ch in next_chars { + if Some(kind(ch)) == word_kind && ch != '\n' { + end += ch.len_utf8(); + } else { + break; + } + } + + (start..end, word_kind) + } + + pub fn as_singleton(&self) -> Option<(&ExcerptId, u64, &BufferSnapshot)> { + if self.singleton { + self.excerpts + .iter() + .next() + .map(|e| (&e.id, e.buffer_id, &e.buffer)) + } else { + None + } + } + + pub fn len(&self) -> usize { + self.excerpts.summary().text.len + } + + pub fn is_empty(&self) -> bool { + self.excerpts.summary().text.len == 0 + } + + pub fn max_buffer_row(&self) -> u32 { + self.excerpts.summary().max_buffer_row + } + + pub fn clip_offset(&self, offset: usize, bias: Bias) -> usize { + if let Some((_, _, buffer)) = self.as_singleton() { + return buffer.clip_offset(offset, bias); + } + + let mut cursor = self.excerpts.cursor::(); + cursor.seek(&offset, Bias::Right, &()); + let overshoot = if let Some(excerpt) = cursor.item() { + let excerpt_start = excerpt.range.context.start.to_offset(&excerpt.buffer); + let buffer_offset = excerpt + .buffer + .clip_offset(excerpt_start + (offset - cursor.start()), bias); + buffer_offset.saturating_sub(excerpt_start) + } else { + 0 + }; + cursor.start() + overshoot + } + + pub fn clip_point(&self, point: Point, bias: Bias) -> Point { + if let Some((_, _, buffer)) = self.as_singleton() { + return buffer.clip_point(point, bias); + } + + let mut cursor = self.excerpts.cursor::(); + cursor.seek(&point, Bias::Right, &()); + let overshoot = if let Some(excerpt) = cursor.item() { + let excerpt_start = excerpt.range.context.start.to_point(&excerpt.buffer); + let buffer_point = excerpt + .buffer + .clip_point(excerpt_start + (point - cursor.start()), bias); + buffer_point.saturating_sub(excerpt_start) + } else { + Point::zero() + }; + *cursor.start() + overshoot + } + + pub fn clip_offset_utf16(&self, offset: OffsetUtf16, bias: Bias) -> OffsetUtf16 { + if let Some((_, _, buffer)) = self.as_singleton() { + return buffer.clip_offset_utf16(offset, bias); + } + + let mut cursor = self.excerpts.cursor::(); + cursor.seek(&offset, Bias::Right, &()); + let overshoot = if let Some(excerpt) = cursor.item() { + let excerpt_start = excerpt.range.context.start.to_offset_utf16(&excerpt.buffer); + let buffer_offset = excerpt + .buffer + .clip_offset_utf16(excerpt_start + (offset - cursor.start()), bias); + OffsetUtf16(buffer_offset.0.saturating_sub(excerpt_start.0)) + } else { + OffsetUtf16(0) + }; + *cursor.start() + overshoot + } + + pub fn clip_point_utf16(&self, point: Unclipped, bias: Bias) -> PointUtf16 { + if let Some((_, _, buffer)) = self.as_singleton() { + return buffer.clip_point_utf16(point, bias); + } + + let mut cursor = self.excerpts.cursor::(); + cursor.seek(&point.0, Bias::Right, &()); + let overshoot = if let Some(excerpt) = cursor.item() { + let excerpt_start = excerpt + .buffer + .offset_to_point_utf16(excerpt.range.context.start.to_offset(&excerpt.buffer)); + let buffer_point = excerpt + .buffer + .clip_point_utf16(Unclipped(excerpt_start + (point.0 - cursor.start())), bias); + buffer_point.saturating_sub(excerpt_start) + } else { + PointUtf16::zero() + }; + *cursor.start() + overshoot + } + + pub fn bytes_in_range(&self, range: Range) -> MultiBufferBytes { + let range = range.start.to_offset(self)..range.end.to_offset(self); + let mut excerpts = self.excerpts.cursor::(); + excerpts.seek(&range.start, Bias::Right, &()); + + let mut chunk = &[][..]; + let excerpt_bytes = if let Some(excerpt) = excerpts.item() { + let mut excerpt_bytes = excerpt + .bytes_in_range(range.start - excerpts.start()..range.end - excerpts.start()); + chunk = excerpt_bytes.next().unwrap_or(&[][..]); + Some(excerpt_bytes) + } else { + None + }; + MultiBufferBytes { + range, + excerpts, + excerpt_bytes, + chunk, + } + } + + pub fn reversed_bytes_in_range( + &self, + range: Range, + ) -> ReversedMultiBufferBytes { + let range = range.start.to_offset(self)..range.end.to_offset(self); + let mut excerpts = self.excerpts.cursor::(); + excerpts.seek(&range.end, Bias::Left, &()); + + let mut chunk = &[][..]; + let excerpt_bytes = if let Some(excerpt) = excerpts.item() { + let mut excerpt_bytes = excerpt.reversed_bytes_in_range( + range.start - excerpts.start()..range.end - excerpts.start(), + ); + chunk = excerpt_bytes.next().unwrap_or(&[][..]); + Some(excerpt_bytes) + } else { + None + }; + + ReversedMultiBufferBytes { + range, + excerpts, + excerpt_bytes, + chunk, + } + } + + pub fn buffer_rows(&self, start_row: u32) -> MultiBufferRows { + let mut result = MultiBufferRows { + buffer_row_range: 0..0, + excerpts: self.excerpts.cursor(), + }; + result.seek(start_row); + result + } + + pub fn chunks(&self, range: Range, language_aware: bool) -> MultiBufferChunks { + let range = range.start.to_offset(self)..range.end.to_offset(self); + let mut chunks = MultiBufferChunks { + range: range.clone(), + excerpts: self.excerpts.cursor(), + excerpt_chunks: None, + language_aware, + }; + chunks.seek(range.start); + chunks + } + + pub fn offset_to_point(&self, offset: usize) -> Point { + if let Some((_, _, buffer)) = self.as_singleton() { + return buffer.offset_to_point(offset); + } + + let mut cursor = self.excerpts.cursor::<(usize, Point)>(); + cursor.seek(&offset, Bias::Right, &()); + if let Some(excerpt) = cursor.item() { + let (start_offset, start_point) = cursor.start(); + let overshoot = offset - start_offset; + let excerpt_start_offset = excerpt.range.context.start.to_offset(&excerpt.buffer); + let excerpt_start_point = excerpt.range.context.start.to_point(&excerpt.buffer); + let buffer_point = excerpt + .buffer + .offset_to_point(excerpt_start_offset + overshoot); + *start_point + (buffer_point - excerpt_start_point) + } else { + self.excerpts.summary().text.lines + } + } + + pub fn offset_to_point_utf16(&self, offset: usize) -> PointUtf16 { + if let Some((_, _, buffer)) = self.as_singleton() { + return buffer.offset_to_point_utf16(offset); + } + + let mut cursor = self.excerpts.cursor::<(usize, PointUtf16)>(); + cursor.seek(&offset, Bias::Right, &()); + if let Some(excerpt) = cursor.item() { + let (start_offset, start_point) = cursor.start(); + let overshoot = offset - start_offset; + let excerpt_start_offset = excerpt.range.context.start.to_offset(&excerpt.buffer); + let excerpt_start_point = excerpt.range.context.start.to_point_utf16(&excerpt.buffer); + let buffer_point = excerpt + .buffer + .offset_to_point_utf16(excerpt_start_offset + overshoot); + *start_point + (buffer_point - excerpt_start_point) + } else { + self.excerpts.summary().text.lines_utf16() + } + } + + pub fn point_to_point_utf16(&self, point: Point) -> PointUtf16 { + if let Some((_, _, buffer)) = self.as_singleton() { + return buffer.point_to_point_utf16(point); + } + + let mut cursor = self.excerpts.cursor::<(Point, PointUtf16)>(); + cursor.seek(&point, Bias::Right, &()); + if let Some(excerpt) = cursor.item() { + let (start_offset, start_point) = cursor.start(); + let overshoot = point - start_offset; + let excerpt_start_point = excerpt.range.context.start.to_point(&excerpt.buffer); + let excerpt_start_point_utf16 = + excerpt.range.context.start.to_point_utf16(&excerpt.buffer); + let buffer_point = excerpt + .buffer + .point_to_point_utf16(excerpt_start_point + overshoot); + *start_point + (buffer_point - excerpt_start_point_utf16) + } else { + self.excerpts.summary().text.lines_utf16() + } + } + + pub fn point_to_offset(&self, point: Point) -> usize { + if let Some((_, _, buffer)) = self.as_singleton() { + return buffer.point_to_offset(point); + } + + let mut cursor = self.excerpts.cursor::<(Point, usize)>(); + cursor.seek(&point, Bias::Right, &()); + if let Some(excerpt) = cursor.item() { + let (start_point, start_offset) = cursor.start(); + let overshoot = point - start_point; + let excerpt_start_offset = excerpt.range.context.start.to_offset(&excerpt.buffer); + let excerpt_start_point = excerpt.range.context.start.to_point(&excerpt.buffer); + let buffer_offset = excerpt + .buffer + .point_to_offset(excerpt_start_point + overshoot); + *start_offset + buffer_offset - excerpt_start_offset + } else { + self.excerpts.summary().text.len + } + } + + pub fn offset_utf16_to_offset(&self, offset_utf16: OffsetUtf16) -> usize { + if let Some((_, _, buffer)) = self.as_singleton() { + return buffer.offset_utf16_to_offset(offset_utf16); + } + + let mut cursor = self.excerpts.cursor::<(OffsetUtf16, usize)>(); + cursor.seek(&offset_utf16, Bias::Right, &()); + if let Some(excerpt) = cursor.item() { + let (start_offset_utf16, start_offset) = cursor.start(); + let overshoot = offset_utf16 - start_offset_utf16; + let excerpt_start_offset = excerpt.range.context.start.to_offset(&excerpt.buffer); + let excerpt_start_offset_utf16 = + excerpt.buffer.offset_to_offset_utf16(excerpt_start_offset); + let buffer_offset = excerpt + .buffer + .offset_utf16_to_offset(excerpt_start_offset_utf16 + overshoot); + *start_offset + (buffer_offset - excerpt_start_offset) + } else { + self.excerpts.summary().text.len + } + } + + pub fn offset_to_offset_utf16(&self, offset: usize) -> OffsetUtf16 { + if let Some((_, _, buffer)) = self.as_singleton() { + return buffer.offset_to_offset_utf16(offset); + } + + let mut cursor = self.excerpts.cursor::<(usize, OffsetUtf16)>(); + cursor.seek(&offset, Bias::Right, &()); + if let Some(excerpt) = cursor.item() { + let (start_offset, start_offset_utf16) = cursor.start(); + let overshoot = offset - start_offset; + let excerpt_start_offset_utf16 = + excerpt.range.context.start.to_offset_utf16(&excerpt.buffer); + let excerpt_start_offset = excerpt + .buffer + .offset_utf16_to_offset(excerpt_start_offset_utf16); + let buffer_offset_utf16 = excerpt + .buffer + .offset_to_offset_utf16(excerpt_start_offset + overshoot); + *start_offset_utf16 + (buffer_offset_utf16 - excerpt_start_offset_utf16) + } else { + self.excerpts.summary().text.len_utf16 + } + } + + pub fn point_utf16_to_offset(&self, point: PointUtf16) -> usize { + if let Some((_, _, buffer)) = self.as_singleton() { + return buffer.point_utf16_to_offset(point); + } + + let mut cursor = self.excerpts.cursor::<(PointUtf16, usize)>(); + cursor.seek(&point, Bias::Right, &()); + if let Some(excerpt) = cursor.item() { + let (start_point, start_offset) = cursor.start(); + let overshoot = point - start_point; + let excerpt_start_offset = excerpt.range.context.start.to_offset(&excerpt.buffer); + let excerpt_start_point = excerpt + .buffer + .offset_to_point_utf16(excerpt.range.context.start.to_offset(&excerpt.buffer)); + let buffer_offset = excerpt + .buffer + .point_utf16_to_offset(excerpt_start_point + overshoot); + *start_offset + (buffer_offset - excerpt_start_offset) + } else { + self.excerpts.summary().text.len + } + } + + pub fn point_to_buffer_offset( + &self, + point: T, + ) -> Option<(&BufferSnapshot, usize)> { + let offset = point.to_offset(&self); + let mut cursor = self.excerpts.cursor::(); + cursor.seek(&offset, Bias::Right, &()); + if cursor.item().is_none() { + cursor.prev(&()); + } + + cursor.item().map(|excerpt| { + let excerpt_start = excerpt.range.context.start.to_offset(&excerpt.buffer); + let buffer_point = excerpt_start + offset - *cursor.start(); + (&excerpt.buffer, buffer_point) + }) + } + + pub fn suggested_indents( + &self, + rows: impl IntoIterator, + cx: &AppContext, + ) -> BTreeMap { + let mut result = BTreeMap::new(); + + let mut rows_for_excerpt = Vec::new(); + let mut cursor = self.excerpts.cursor::(); + let mut rows = rows.into_iter().peekable(); + let mut prev_row = u32::MAX; + let mut prev_language_indent_size = IndentSize::default(); + + while let Some(row) = rows.next() { + cursor.seek(&Point::new(row, 0), Bias::Right, &()); + let excerpt = match cursor.item() { + Some(excerpt) => excerpt, + _ => continue, + }; + + // Retrieve the language and indent size once for each disjoint region being indented. + let single_indent_size = if row.saturating_sub(1) == prev_row { + prev_language_indent_size + } else { + excerpt + .buffer + .language_indent_size_at(Point::new(row, 0), cx) + }; + prev_language_indent_size = single_indent_size; + prev_row = row; + + let start_buffer_row = excerpt.range.context.start.to_point(&excerpt.buffer).row; + let start_multibuffer_row = cursor.start().row; + + rows_for_excerpt.push(row); + while let Some(next_row) = rows.peek().copied() { + if cursor.end(&()).row > next_row { + rows_for_excerpt.push(next_row); + rows.next(); + } else { + break; + } + } + + let buffer_rows = rows_for_excerpt + .drain(..) + .map(|row| start_buffer_row + row - start_multibuffer_row); + let buffer_indents = excerpt + .buffer + .suggested_indents(buffer_rows, single_indent_size); + let multibuffer_indents = buffer_indents + .into_iter() + .map(|(row, indent)| (start_multibuffer_row + row - start_buffer_row, indent)); + result.extend(multibuffer_indents); + } + + result + } + + pub fn indent_size_for_line(&self, row: u32) -> IndentSize { + if let Some((buffer, range)) = self.buffer_line_for_row(row) { + let mut size = buffer.indent_size_for_line(range.start.row); + size.len = size + .len + .min(range.end.column) + .saturating_sub(range.start.column); + size + } else { + IndentSize::spaces(0) + } + } + + pub fn prev_non_blank_row(&self, mut row: u32) -> Option { + while row > 0 { + row -= 1; + if !self.is_line_blank(row) { + return Some(row); + } + } + None + } + + pub fn line_len(&self, row: u32) -> u32 { + if let Some((_, range)) = self.buffer_line_for_row(row) { + range.end.column - range.start.column + } else { + 0 + } + } + + pub fn buffer_line_for_row(&self, row: u32) -> Option<(&BufferSnapshot, Range)> { + let mut cursor = self.excerpts.cursor::(); + let point = Point::new(row, 0); + cursor.seek(&point, Bias::Right, &()); + if cursor.item().is_none() && *cursor.start() == point { + cursor.prev(&()); + } + if let Some(excerpt) = cursor.item() { + let overshoot = row - cursor.start().row; + let excerpt_start = excerpt.range.context.start.to_point(&excerpt.buffer); + let excerpt_end = excerpt.range.context.end.to_point(&excerpt.buffer); + let buffer_row = excerpt_start.row + overshoot; + let line_start = Point::new(buffer_row, 0); + let line_end = Point::new(buffer_row, excerpt.buffer.line_len(buffer_row)); + return Some(( + &excerpt.buffer, + line_start.max(excerpt_start)..line_end.min(excerpt_end), + )); + } + None + } + + pub fn max_point(&self) -> Point { + self.text_summary().lines + } + + pub fn text_summary(&self) -> TextSummary { + self.excerpts.summary().text.clone() + } + + pub fn text_summary_for_range(&self, range: Range) -> D + where + D: TextDimension, + O: ToOffset, + { + let mut summary = D::default(); + let mut range = range.start.to_offset(self)..range.end.to_offset(self); + let mut cursor = self.excerpts.cursor::(); + cursor.seek(&range.start, Bias::Right, &()); + if let Some(excerpt) = cursor.item() { + let mut end_before_newline = cursor.end(&()); + if excerpt.has_trailing_newline { + end_before_newline -= 1; + } + + let excerpt_start = excerpt.range.context.start.to_offset(&excerpt.buffer); + let start_in_excerpt = excerpt_start + (range.start - cursor.start()); + let end_in_excerpt = + excerpt_start + (cmp::min(end_before_newline, range.end) - cursor.start()); + summary.add_assign( + &excerpt + .buffer + .text_summary_for_range(start_in_excerpt..end_in_excerpt), + ); + + if range.end > end_before_newline { + summary.add_assign(&D::from_text_summary(&TextSummary::from("\n"))); + } + + cursor.next(&()); + } + + if range.end > *cursor.start() { + summary.add_assign(&D::from_text_summary(&cursor.summary::<_, TextSummary>( + &range.end, + Bias::Right, + &(), + ))); + if let Some(excerpt) = cursor.item() { + range.end = cmp::max(*cursor.start(), range.end); + + let excerpt_start = excerpt.range.context.start.to_offset(&excerpt.buffer); + let end_in_excerpt = excerpt_start + (range.end - cursor.start()); + summary.add_assign( + &excerpt + .buffer + .text_summary_for_range(excerpt_start..end_in_excerpt), + ); + } + } + + summary + } + + pub fn summary_for_anchor(&self, anchor: &Anchor) -> D + where + D: TextDimension + Ord + Sub, + { + let mut cursor = self.excerpts.cursor::(); + let locator = self.excerpt_locator_for_id(anchor.excerpt_id); + + cursor.seek(locator, Bias::Left, &()); + if cursor.item().is_none() { + cursor.next(&()); + } + + let mut position = D::from_text_summary(&cursor.start().text); + if let Some(excerpt) = cursor.item() { + if excerpt.id == anchor.excerpt_id { + let excerpt_buffer_start = + excerpt.range.context.start.summary::(&excerpt.buffer); + let excerpt_buffer_end = excerpt.range.context.end.summary::(&excerpt.buffer); + let buffer_position = cmp::min( + excerpt_buffer_end, + anchor.text_anchor.summary::(&excerpt.buffer), + ); + if buffer_position > excerpt_buffer_start { + position.add_assign(&(buffer_position - excerpt_buffer_start)); + } + } + } + position + } + + pub fn summaries_for_anchors<'a, D, I>(&'a self, anchors: I) -> Vec + where + D: TextDimension + Ord + Sub, + I: 'a + IntoIterator, + { + if let Some((_, _, buffer)) = self.as_singleton() { + return buffer + .summaries_for_anchors(anchors.into_iter().map(|a| &a.text_anchor)) + .collect(); + } + + let mut anchors = anchors.into_iter().peekable(); + let mut cursor = self.excerpts.cursor::(); + let mut summaries = Vec::new(); + while let Some(anchor) = anchors.peek() { + let excerpt_id = anchor.excerpt_id; + let excerpt_anchors = iter::from_fn(|| { + let anchor = anchors.peek()?; + if anchor.excerpt_id == excerpt_id { + Some(&anchors.next().unwrap().text_anchor) + } else { + None + } + }); + + let locator = self.excerpt_locator_for_id(excerpt_id); + cursor.seek_forward(locator, Bias::Left, &()); + if cursor.item().is_none() { + cursor.next(&()); + } + + let position = D::from_text_summary(&cursor.start().text); + if let Some(excerpt) = cursor.item() { + if excerpt.id == excerpt_id { + let excerpt_buffer_start = + excerpt.range.context.start.summary::(&excerpt.buffer); + let excerpt_buffer_end = + excerpt.range.context.end.summary::(&excerpt.buffer); + summaries.extend( + excerpt + .buffer + .summaries_for_anchors::(excerpt_anchors) + .map(move |summary| { + let summary = cmp::min(excerpt_buffer_end.clone(), summary); + let mut position = position.clone(); + let excerpt_buffer_start = excerpt_buffer_start.clone(); + if summary > excerpt_buffer_start { + position.add_assign(&(summary - excerpt_buffer_start)); + } + position + }), + ); + continue; + } + } + + summaries.extend(excerpt_anchors.map(|_| position.clone())); + } + + summaries + } + + pub fn refresh_anchors<'a, I>(&'a self, anchors: I) -> Vec<(usize, Anchor, bool)> + where + I: 'a + IntoIterator, + { + let mut anchors = anchors.into_iter().enumerate().peekable(); + let mut cursor = self.excerpts.cursor::>(); + cursor.next(&()); + + let mut result = Vec::new(); + + while let Some((_, anchor)) = anchors.peek() { + let old_excerpt_id = anchor.excerpt_id; + + // Find the location where this anchor's excerpt should be. + let old_locator = self.excerpt_locator_for_id(old_excerpt_id); + cursor.seek_forward(&Some(old_locator), Bias::Left, &()); + + if cursor.item().is_none() { + cursor.next(&()); + } + + let next_excerpt = cursor.item(); + let prev_excerpt = cursor.prev_item(); + + // Process all of the anchors for this excerpt. + while let Some((_, anchor)) = anchors.peek() { + if anchor.excerpt_id != old_excerpt_id { + break; + } + let (anchor_ix, anchor) = anchors.next().unwrap(); + let mut anchor = *anchor; + + // Leave min and max anchors unchanged if invalid or + // if the old excerpt still exists at this location + let mut kept_position = next_excerpt + .map_or(false, |e| e.id == old_excerpt_id && e.contains(&anchor)) + || old_excerpt_id == ExcerptId::max() + || old_excerpt_id == ExcerptId::min(); + + // If the old excerpt no longer exists at this location, then attempt to + // find an equivalent position for this anchor in an adjacent excerpt. + if !kept_position { + for excerpt in [next_excerpt, prev_excerpt].iter().filter_map(|e| *e) { + if excerpt.contains(&anchor) { + anchor.excerpt_id = excerpt.id.clone(); + kept_position = true; + break; + } + } + } + + // If there's no adjacent excerpt that contains the anchor's position, + // then report that the anchor has lost its position. + if !kept_position { + anchor = if let Some(excerpt) = next_excerpt { + let mut text_anchor = excerpt + .range + .context + .start + .bias(anchor.text_anchor.bias, &excerpt.buffer); + if text_anchor + .cmp(&excerpt.range.context.end, &excerpt.buffer) + .is_gt() + { + text_anchor = excerpt.range.context.end; + } + Anchor { + buffer_id: Some(excerpt.buffer_id), + excerpt_id: excerpt.id.clone(), + text_anchor, + } + } else if let Some(excerpt) = prev_excerpt { + let mut text_anchor = excerpt + .range + .context + .end + .bias(anchor.text_anchor.bias, &excerpt.buffer); + if text_anchor + .cmp(&excerpt.range.context.start, &excerpt.buffer) + .is_lt() + { + text_anchor = excerpt.range.context.start; + } + Anchor { + buffer_id: Some(excerpt.buffer_id), + excerpt_id: excerpt.id.clone(), + text_anchor, + } + } else if anchor.text_anchor.bias == Bias::Left { + Anchor::min() + } else { + Anchor::max() + }; + } + + result.push((anchor_ix, anchor, kept_position)); + } + } + result.sort_unstable_by(|a, b| a.1.cmp(&b.1, self)); + result + } + + pub fn anchor_before(&self, position: T) -> Anchor { + self.anchor_at(position, Bias::Left) + } + + pub fn anchor_after(&self, position: T) -> Anchor { + self.anchor_at(position, Bias::Right) + } + + pub fn anchor_at(&self, position: T, mut bias: Bias) -> Anchor { + let offset = position.to_offset(self); + if let Some((excerpt_id, buffer_id, buffer)) = self.as_singleton() { + return Anchor { + buffer_id: Some(buffer_id), + excerpt_id: excerpt_id.clone(), + text_anchor: buffer.anchor_at(offset, bias), + }; + } + + let mut cursor = self.excerpts.cursor::<(usize, Option)>(); + cursor.seek(&offset, Bias::Right, &()); + if cursor.item().is_none() && offset == cursor.start().0 && bias == Bias::Left { + cursor.prev(&()); + } + if let Some(excerpt) = cursor.item() { + let mut overshoot = offset.saturating_sub(cursor.start().0); + if excerpt.has_trailing_newline && offset == cursor.end(&()).0 { + overshoot -= 1; + bias = Bias::Right; + } + + let buffer_start = excerpt.range.context.start.to_offset(&excerpt.buffer); + let text_anchor = + excerpt.clip_anchor(excerpt.buffer.anchor_at(buffer_start + overshoot, bias)); + Anchor { + buffer_id: Some(excerpt.buffer_id), + excerpt_id: excerpt.id.clone(), + text_anchor, + } + } else if offset == 0 && bias == Bias::Left { + Anchor::min() + } else { + Anchor::max() + } + } + + pub fn anchor_in_excerpt(&self, excerpt_id: ExcerptId, text_anchor: text::Anchor) -> Anchor { + let locator = self.excerpt_locator_for_id(excerpt_id); + let mut cursor = self.excerpts.cursor::>(); + cursor.seek(locator, Bias::Left, &()); + if let Some(excerpt) = cursor.item() { + if excerpt.id == excerpt_id { + let text_anchor = excerpt.clip_anchor(text_anchor); + drop(cursor); + return Anchor { + buffer_id: Some(excerpt.buffer_id), + excerpt_id, + text_anchor, + }; + } + } + panic!("excerpt not found"); + } + + pub fn can_resolve(&self, anchor: &Anchor) -> bool { + if anchor.excerpt_id == ExcerptId::min() || anchor.excerpt_id == ExcerptId::max() { + true + } else if let Some(excerpt) = self.excerpt(anchor.excerpt_id) { + excerpt.buffer.can_resolve(&anchor.text_anchor) + } else { + false + } + } + + pub fn excerpts( + &self, + ) -> impl Iterator)> { + self.excerpts + .iter() + .map(|excerpt| (excerpt.id, &excerpt.buffer, excerpt.range.clone())) + } + + pub fn excerpt_boundaries_in_range( + &self, + range: R, + ) -> impl Iterator + '_ + where + R: RangeBounds, + T: ToOffset, + { + let start_offset; + let start = match range.start_bound() { + Bound::Included(start) => { + start_offset = start.to_offset(self); + Bound::Included(start_offset) + } + Bound::Excluded(start) => { + start_offset = start.to_offset(self); + Bound::Excluded(start_offset) + } + Bound::Unbounded => { + start_offset = 0; + Bound::Unbounded + } + }; + let end = match range.end_bound() { + Bound::Included(end) => Bound::Included(end.to_offset(self)), + Bound::Excluded(end) => Bound::Excluded(end.to_offset(self)), + Bound::Unbounded => Bound::Unbounded, + }; + let bounds = (start, end); + + let mut cursor = self.excerpts.cursor::<(usize, Point)>(); + cursor.seek(&start_offset, Bias::Right, &()); + if cursor.item().is_none() { + cursor.prev(&()); + } + if !bounds.contains(&cursor.start().0) { + cursor.next(&()); + } + + let mut prev_buffer_id = cursor.prev_item().map(|excerpt| excerpt.buffer_id); + std::iter::from_fn(move || { + if self.singleton { + None + } else if bounds.contains(&cursor.start().0) { + let excerpt = cursor.item()?; + let starts_new_buffer = Some(excerpt.buffer_id) != prev_buffer_id; + let boundary = ExcerptBoundary { + id: excerpt.id.clone(), + row: cursor.start().1.row, + buffer: excerpt.buffer.clone(), + range: excerpt.range.clone(), + starts_new_buffer, + }; + + prev_buffer_id = Some(excerpt.buffer_id); + cursor.next(&()); + Some(boundary) + } else { + None + } + }) + } + + pub fn edit_count(&self) -> usize { + self.edit_count + } + + pub fn parse_count(&self) -> usize { + self.parse_count + } + + /// Returns the smallest enclosing bracket ranges containing the given range or + /// None if no brackets contain range or the range is not contained in a single + /// excerpt + pub fn innermost_enclosing_bracket_ranges( + &self, + range: Range, + ) -> Option<(Range, Range)> { + let range = range.start.to_offset(self)..range.end.to_offset(self); + + // Get the ranges of the innermost pair of brackets. + let mut result: Option<(Range, Range)> = None; + + let Some(enclosing_bracket_ranges) = self.enclosing_bracket_ranges(range.clone()) else { + return None; + }; + + for (open, close) in enclosing_bracket_ranges { + let len = close.end - open.start; + + if let Some((existing_open, existing_close)) = &result { + let existing_len = existing_close.end - existing_open.start; + if len > existing_len { + continue; + } + } + + result = Some((open, close)); + } + + result + } + + /// Returns enclosing bracket ranges containing the given range or returns None if the range is + /// not contained in a single excerpt + pub fn enclosing_bracket_ranges<'a, T: ToOffset>( + &'a self, + range: Range, + ) -> Option, Range)> + 'a> { + let range = range.start.to_offset(self)..range.end.to_offset(self); + + self.bracket_ranges(range.clone()).map(|range_pairs| { + range_pairs + .filter(move |(open, close)| open.start <= range.start && close.end >= range.end) + }) + } + + /// Returns bracket range pairs overlapping the given `range` or returns None if the `range` is + /// not contained in a single excerpt + pub fn bracket_ranges<'a, T: ToOffset>( + &'a self, + range: Range, + ) -> Option, Range)> + 'a> { + let range = range.start.to_offset(self)..range.end.to_offset(self); + let excerpt = self.excerpt_containing(range.clone()); + excerpt.map(|(excerpt, excerpt_offset)| { + let excerpt_buffer_start = excerpt.range.context.start.to_offset(&excerpt.buffer); + let excerpt_buffer_end = excerpt_buffer_start + excerpt.text_summary.len; + + let start_in_buffer = excerpt_buffer_start + range.start.saturating_sub(excerpt_offset); + let end_in_buffer = excerpt_buffer_start + range.end.saturating_sub(excerpt_offset); + + excerpt + .buffer + .bracket_ranges(start_in_buffer..end_in_buffer) + .filter_map(move |(start_bracket_range, end_bracket_range)| { + if start_bracket_range.start < excerpt_buffer_start + || end_bracket_range.end > excerpt_buffer_end + { + return None; + } + + let mut start_bracket_range = start_bracket_range.clone(); + start_bracket_range.start = + excerpt_offset + (start_bracket_range.start - excerpt_buffer_start); + start_bracket_range.end = + excerpt_offset + (start_bracket_range.end - excerpt_buffer_start); + + let mut end_bracket_range = end_bracket_range.clone(); + end_bracket_range.start = + excerpt_offset + (end_bracket_range.start - excerpt_buffer_start); + end_bracket_range.end = + excerpt_offset + (end_bracket_range.end - excerpt_buffer_start); + Some((start_bracket_range, end_bracket_range)) + }) + }) + } + + pub fn diagnostics_update_count(&self) -> usize { + self.diagnostics_update_count + } + + pub fn git_diff_update_count(&self) -> usize { + self.git_diff_update_count + } + + pub fn trailing_excerpt_update_count(&self) -> usize { + self.trailing_excerpt_update_count + } + + pub fn file_at<'a, T: ToOffset>(&'a self, point: T) -> Option<&'a Arc> { + self.point_to_buffer_offset(point) + .and_then(|(buffer, _)| buffer.file()) + } + + pub fn language_at<'a, T: ToOffset>(&'a self, point: T) -> Option<&'a Arc> { + self.point_to_buffer_offset(point) + .and_then(|(buffer, offset)| buffer.language_at(offset)) + } + + pub fn settings_at<'a, T: ToOffset>( + &'a self, + point: T, + cx: &'a AppContext, + ) -> &'a LanguageSettings { + let mut language = None; + let mut file = None; + if let Some((buffer, offset)) = self.point_to_buffer_offset(point) { + language = buffer.language_at(offset); + file = buffer.file(); + } + language_settings(language, file, cx) + } + + pub fn language_scope_at<'a, T: ToOffset>(&'a self, point: T) -> Option { + self.point_to_buffer_offset(point) + .and_then(|(buffer, offset)| buffer.language_scope_at(offset)) + } + + pub fn language_indent_size_at( + &self, + position: T, + cx: &AppContext, + ) -> Option { + let (buffer_snapshot, offset) = self.point_to_buffer_offset(position)?; + Some(buffer_snapshot.language_indent_size_at(offset, cx)) + } + + pub fn is_dirty(&self) -> bool { + self.is_dirty + } + + pub fn has_conflict(&self) -> bool { + self.has_conflict + } + + pub fn diagnostic_group<'a, O>( + &'a self, + group_id: usize, + ) -> impl Iterator> + 'a + where + O: text::FromAnchor + 'a, + { + self.as_singleton() + .into_iter() + .flat_map(move |(_, _, buffer)| buffer.diagnostic_group(group_id)) + } + + pub fn diagnostics_in_range<'a, T, O>( + &'a self, + range: Range, + reversed: bool, + ) -> impl Iterator> + 'a + where + T: 'a + ToOffset, + O: 'a + text::FromAnchor + Ord, + { + self.as_singleton() + .into_iter() + .flat_map(move |(_, _, buffer)| { + buffer.diagnostics_in_range( + range.start.to_offset(self)..range.end.to_offset(self), + reversed, + ) + }) + } + + pub fn has_git_diffs(&self) -> bool { + for excerpt in self.excerpts.iter() { + if !excerpt.buffer.git_diff.is_empty() { + return true; + } + } + false + } + + pub fn git_diff_hunks_in_range_rev<'a>( + &'a self, + row_range: Range, + ) -> impl 'a + Iterator> { + let mut cursor = self.excerpts.cursor::(); + + cursor.seek(&Point::new(row_range.end, 0), Bias::Left, &()); + if cursor.item().is_none() { + cursor.prev(&()); + } + + std::iter::from_fn(move || { + let excerpt = cursor.item()?; + let multibuffer_start = *cursor.start(); + let multibuffer_end = multibuffer_start + excerpt.text_summary.lines; + if multibuffer_start.row >= row_range.end { + return None; + } + + let mut buffer_start = excerpt.range.context.start; + let mut buffer_end = excerpt.range.context.end; + let excerpt_start_point = buffer_start.to_point(&excerpt.buffer); + let excerpt_end_point = excerpt_start_point + excerpt.text_summary.lines; + + if row_range.start > multibuffer_start.row { + let buffer_start_point = + excerpt_start_point + Point::new(row_range.start - multibuffer_start.row, 0); + buffer_start = excerpt.buffer.anchor_before(buffer_start_point); + } + + if row_range.end < multibuffer_end.row { + let buffer_end_point = + excerpt_start_point + Point::new(row_range.end - multibuffer_start.row, 0); + buffer_end = excerpt.buffer.anchor_before(buffer_end_point); + } + + let buffer_hunks = excerpt + .buffer + .git_diff_hunks_intersecting_range_rev(buffer_start..buffer_end) + .filter_map(move |hunk| { + let start = multibuffer_start.row + + hunk + .buffer_range + .start + .saturating_sub(excerpt_start_point.row); + let end = multibuffer_start.row + + hunk + .buffer_range + .end + .min(excerpt_end_point.row + 1) + .saturating_sub(excerpt_start_point.row); + + Some(DiffHunk { + buffer_range: start..end, + diff_base_byte_range: hunk.diff_base_byte_range.clone(), + }) + }); + + cursor.prev(&()); + + Some(buffer_hunks) + }) + .flatten() + } + + pub fn git_diff_hunks_in_range<'a>( + &'a self, + row_range: Range, + ) -> impl 'a + Iterator> { + let mut cursor = self.excerpts.cursor::(); + + cursor.seek(&Point::new(row_range.start, 0), Bias::Right, &()); + + std::iter::from_fn(move || { + let excerpt = cursor.item()?; + let multibuffer_start = *cursor.start(); + let multibuffer_end = multibuffer_start + excerpt.text_summary.lines; + if multibuffer_start.row >= row_range.end { + return None; + } + + let mut buffer_start = excerpt.range.context.start; + let mut buffer_end = excerpt.range.context.end; + let excerpt_start_point = buffer_start.to_point(&excerpt.buffer); + let excerpt_end_point = excerpt_start_point + excerpt.text_summary.lines; + + if row_range.start > multibuffer_start.row { + let buffer_start_point = + excerpt_start_point + Point::new(row_range.start - multibuffer_start.row, 0); + buffer_start = excerpt.buffer.anchor_before(buffer_start_point); + } + + if row_range.end < multibuffer_end.row { + let buffer_end_point = + excerpt_start_point + Point::new(row_range.end - multibuffer_start.row, 0); + buffer_end = excerpt.buffer.anchor_before(buffer_end_point); + } + + let buffer_hunks = excerpt + .buffer + .git_diff_hunks_intersecting_range(buffer_start..buffer_end) + .filter_map(move |hunk| { + let start = multibuffer_start.row + + hunk + .buffer_range + .start + .saturating_sub(excerpt_start_point.row); + let end = multibuffer_start.row + + hunk + .buffer_range + .end + .min(excerpt_end_point.row + 1) + .saturating_sub(excerpt_start_point.row); + + Some(DiffHunk { + buffer_range: start..end, + diff_base_byte_range: hunk.diff_base_byte_range.clone(), + }) + }); + + cursor.next(&()); + + Some(buffer_hunks) + }) + .flatten() + } + + pub fn range_for_syntax_ancestor(&self, range: Range) -> Option> { + let range = range.start.to_offset(self)..range.end.to_offset(self); + + self.excerpt_containing(range.clone()) + .and_then(|(excerpt, excerpt_offset)| { + let excerpt_buffer_start = excerpt.range.context.start.to_offset(&excerpt.buffer); + let excerpt_buffer_end = excerpt_buffer_start + excerpt.text_summary.len; + + let start_in_buffer = + excerpt_buffer_start + range.start.saturating_sub(excerpt_offset); + let end_in_buffer = excerpt_buffer_start + range.end.saturating_sub(excerpt_offset); + let mut ancestor_buffer_range = excerpt + .buffer + .range_for_syntax_ancestor(start_in_buffer..end_in_buffer)?; + ancestor_buffer_range.start = + cmp::max(ancestor_buffer_range.start, excerpt_buffer_start); + ancestor_buffer_range.end = cmp::min(ancestor_buffer_range.end, excerpt_buffer_end); + + let start = excerpt_offset + (ancestor_buffer_range.start - excerpt_buffer_start); + let end = excerpt_offset + (ancestor_buffer_range.end - excerpt_buffer_start); + Some(start..end) + }) + } + + pub fn outline(&self, theme: Option<&SyntaxTheme>) -> Option> { + let (excerpt_id, _, buffer) = self.as_singleton()?; + let outline = buffer.outline(theme)?; + Some(Outline::new( + outline + .items + .into_iter() + .map(|item| OutlineItem { + depth: item.depth, + range: self.anchor_in_excerpt(excerpt_id.clone(), item.range.start) + ..self.anchor_in_excerpt(excerpt_id.clone(), item.range.end), + text: item.text, + highlight_ranges: item.highlight_ranges, + name_ranges: item.name_ranges, + }) + .collect(), + )) + } + + pub fn symbols_containing( + &self, + offset: T, + theme: Option<&SyntaxTheme>, + ) -> Option<(u64, Vec>)> { + let anchor = self.anchor_before(offset); + let excerpt_id = anchor.excerpt_id; + let excerpt = self.excerpt(excerpt_id)?; + Some(( + excerpt.buffer_id, + excerpt + .buffer + .symbols_containing(anchor.text_anchor, theme) + .into_iter() + .flatten() + .map(|item| OutlineItem { + depth: item.depth, + range: self.anchor_in_excerpt(excerpt_id, item.range.start) + ..self.anchor_in_excerpt(excerpt_id, item.range.end), + text: item.text, + highlight_ranges: item.highlight_ranges, + name_ranges: item.name_ranges, + }) + .collect(), + )) + } + + fn excerpt_locator_for_id<'a>(&'a self, id: ExcerptId) -> &'a Locator { + if id == ExcerptId::min() { + Locator::min_ref() + } else if id == ExcerptId::max() { + Locator::max_ref() + } else { + let mut cursor = self.excerpt_ids.cursor::(); + cursor.seek(&id, Bias::Left, &()); + if let Some(entry) = cursor.item() { + if entry.id == id { + return &entry.locator; + } + } + panic!("invalid excerpt id {:?}", id) + } + } + + pub fn buffer_id_for_excerpt(&self, excerpt_id: ExcerptId) -> Option { + Some(self.excerpt(excerpt_id)?.buffer_id) + } + + pub fn buffer_for_excerpt(&self, excerpt_id: ExcerptId) -> Option<&BufferSnapshot> { + Some(&self.excerpt(excerpt_id)?.buffer) + } + + fn excerpt<'a>(&'a self, excerpt_id: ExcerptId) -> Option<&'a Excerpt> { + let mut cursor = self.excerpts.cursor::>(); + let locator = self.excerpt_locator_for_id(excerpt_id); + cursor.seek(&Some(locator), Bias::Left, &()); + if let Some(excerpt) = cursor.item() { + if excerpt.id == excerpt_id { + return Some(excerpt); + } + } + None + } + + /// Returns the excerpt containing range and its offset start within the multibuffer or none if `range` spans multiple excerpts + fn excerpt_containing<'a, T: ToOffset>( + &'a self, + range: Range, + ) -> Option<(&'a Excerpt, usize)> { + let range = range.start.to_offset(self)..range.end.to_offset(self); + + let mut cursor = self.excerpts.cursor::(); + cursor.seek(&range.start, Bias::Right, &()); + let start_excerpt = cursor.item(); + + if range.start == range.end { + return start_excerpt.map(|excerpt| (excerpt, *cursor.start())); + } + + cursor.seek(&range.end, Bias::Right, &()); + let end_excerpt = cursor.item(); + + start_excerpt + .zip(end_excerpt) + .and_then(|(start_excerpt, end_excerpt)| { + if start_excerpt.id != end_excerpt.id { + return None; + } + + Some((start_excerpt, *cursor.start())) + }) + } + + pub fn remote_selections_in_range<'a>( + &'a self, + range: &'a Range, + ) -> impl 'a + Iterator)> { + let mut cursor = self.excerpts.cursor::(); + let start_locator = self.excerpt_locator_for_id(range.start.excerpt_id); + let end_locator = self.excerpt_locator_for_id(range.end.excerpt_id); + cursor.seek(start_locator, Bias::Left, &()); + cursor + .take_while(move |excerpt| excerpt.locator <= *end_locator) + .flat_map(move |excerpt| { + let mut query_range = excerpt.range.context.start..excerpt.range.context.end; + if excerpt.id == range.start.excerpt_id { + query_range.start = range.start.text_anchor; + } + if excerpt.id == range.end.excerpt_id { + query_range.end = range.end.text_anchor; + } + + excerpt + .buffer + .remote_selections_in_range(query_range) + .flat_map(move |(replica_id, line_mode, cursor_shape, selections)| { + selections.map(move |selection| { + let mut start = Anchor { + buffer_id: Some(excerpt.buffer_id), + excerpt_id: excerpt.id.clone(), + text_anchor: selection.start, + }; + let mut end = Anchor { + buffer_id: Some(excerpt.buffer_id), + excerpt_id: excerpt.id.clone(), + text_anchor: selection.end, + }; + if range.start.cmp(&start, self).is_gt() { + start = range.start.clone(); + } + if range.end.cmp(&end, self).is_lt() { + end = range.end.clone(); + } + + ( + replica_id, + line_mode, + cursor_shape, + Selection { + id: selection.id, + start, + end, + reversed: selection.reversed, + goal: selection.goal, + }, + ) + }) + }) + }) + } +} + +#[cfg(any(test, feature = "test-support"))] +impl MultiBufferSnapshot { + pub fn random_byte_range(&self, start_offset: usize, rng: &mut impl rand::Rng) -> Range { + let end = self.clip_offset(rng.gen_range(start_offset..=self.len()), Bias::Right); + let start = self.clip_offset(rng.gen_range(start_offset..=end), Bias::Right); + start..end + } +} + +impl History { + fn start_transaction(&mut self, now: Instant) -> Option { + self.transaction_depth += 1; + if self.transaction_depth == 1 { + let id = self.next_transaction_id.tick(); + self.undo_stack.push(Transaction { + id, + buffer_transactions: Default::default(), + first_edit_at: now, + last_edit_at: now, + suppress_grouping: false, + }); + Some(id) + } else { + None + } + } + + fn end_transaction( + &mut self, + now: Instant, + buffer_transactions: HashMap, + ) -> bool { + assert_ne!(self.transaction_depth, 0); + self.transaction_depth -= 1; + if self.transaction_depth == 0 { + if buffer_transactions.is_empty() { + self.undo_stack.pop(); + false + } else { + self.redo_stack.clear(); + let transaction = self.undo_stack.last_mut().unwrap(); + transaction.last_edit_at = now; + for (buffer_id, transaction_id) in buffer_transactions { + transaction + .buffer_transactions + .entry(buffer_id) + .or_insert(transaction_id); + } + true + } + } else { + false + } + } + + fn push_transaction<'a, T>( + &mut self, + buffer_transactions: T, + now: Instant, + cx: &mut ModelContext, + ) where + T: IntoIterator, &'a language2::Transaction)>, + { + assert_eq!(self.transaction_depth, 0); + let transaction = Transaction { + id: self.next_transaction_id.tick(), + buffer_transactions: buffer_transactions + .into_iter() + .map(|(buffer, transaction)| (buffer.read(cx).remote_id(), transaction.id)) + .collect(), + first_edit_at: now, + last_edit_at: now, + suppress_grouping: false, + }; + if !transaction.buffer_transactions.is_empty() { + self.undo_stack.push(transaction); + self.redo_stack.clear(); + } + } + + fn finalize_last_transaction(&mut self) { + if let Some(transaction) = self.undo_stack.last_mut() { + transaction.suppress_grouping = true; + } + } + + fn forget(&mut self, transaction_id: TransactionId) -> Option { + if let Some(ix) = self + .undo_stack + .iter() + .rposition(|transaction| transaction.id == transaction_id) + { + Some(self.undo_stack.remove(ix)) + } else if let Some(ix) = self + .redo_stack + .iter() + .rposition(|transaction| transaction.id == transaction_id) + { + Some(self.redo_stack.remove(ix)) + } else { + None + } + } + + fn transaction_mut(&mut self, transaction_id: TransactionId) -> Option<&mut Transaction> { + self.undo_stack + .iter_mut() + .find(|transaction| transaction.id == transaction_id) + .or_else(|| { + self.redo_stack + .iter_mut() + .find(|transaction| transaction.id == transaction_id) + }) + } + + fn pop_undo(&mut self) -> Option<&mut Transaction> { + assert_eq!(self.transaction_depth, 0); + if let Some(transaction) = self.undo_stack.pop() { + self.redo_stack.push(transaction); + self.redo_stack.last_mut() + } else { + None + } + } + + fn pop_redo(&mut self) -> Option<&mut Transaction> { + assert_eq!(self.transaction_depth, 0); + if let Some(transaction) = self.redo_stack.pop() { + self.undo_stack.push(transaction); + self.undo_stack.last_mut() + } else { + None + } + } + + fn remove_from_undo(&mut self, transaction_id: TransactionId) -> Option<&Transaction> { + let ix = self + .undo_stack + .iter() + .rposition(|transaction| transaction.id == transaction_id)?; + let transaction = self.undo_stack.remove(ix); + self.redo_stack.push(transaction); + self.redo_stack.last() + } + + fn group(&mut self) -> Option { + let mut count = 0; + let mut transactions = self.undo_stack.iter(); + if let Some(mut transaction) = transactions.next_back() { + while let Some(prev_transaction) = transactions.next_back() { + if !prev_transaction.suppress_grouping + && transaction.first_edit_at - prev_transaction.last_edit_at + <= self.group_interval + { + transaction = prev_transaction; + count += 1; + } else { + break; + } + } + } + self.group_trailing(count) + } + + fn group_until(&mut self, transaction_id: TransactionId) { + let mut count = 0; + for transaction in self.undo_stack.iter().rev() { + if transaction.id == transaction_id { + self.group_trailing(count); + break; + } else if transaction.suppress_grouping { + break; + } else { + count += 1; + } + } + } + + fn group_trailing(&mut self, n: usize) -> Option { + let new_len = self.undo_stack.len() - n; + let (transactions_to_keep, transactions_to_merge) = self.undo_stack.split_at_mut(new_len); + if let Some(last_transaction) = transactions_to_keep.last_mut() { + if let Some(transaction) = transactions_to_merge.last() { + last_transaction.last_edit_at = transaction.last_edit_at; + } + for to_merge in transactions_to_merge { + for (buffer_id, transaction_id) in &to_merge.buffer_transactions { + last_transaction + .buffer_transactions + .entry(*buffer_id) + .or_insert(*transaction_id); + } + } + } + + self.undo_stack.truncate(new_len); + self.undo_stack.last().map(|t| t.id) + } +} + +impl Excerpt { + fn new( + id: ExcerptId, + locator: Locator, + buffer_id: u64, + buffer: BufferSnapshot, + range: ExcerptRange, + has_trailing_newline: bool, + ) -> Self { + Excerpt { + id, + locator, + max_buffer_row: range.context.end.to_point(&buffer).row, + text_summary: buffer + .text_summary_for_range::(range.context.to_offset(&buffer)), + buffer_id, + buffer, + range, + has_trailing_newline, + } + } + + fn chunks_in_range(&self, range: Range, language_aware: bool) -> ExcerptChunks { + let content_start = self.range.context.start.to_offset(&self.buffer); + let chunks_start = content_start + range.start; + let chunks_end = content_start + cmp::min(range.end, self.text_summary.len); + + let footer_height = if self.has_trailing_newline + && range.start <= self.text_summary.len + && range.end > self.text_summary.len + { + 1 + } else { + 0 + }; + + let content_chunks = self.buffer.chunks(chunks_start..chunks_end, language_aware); + + ExcerptChunks { + content_chunks, + footer_height, + } + } + + fn bytes_in_range(&self, range: Range) -> ExcerptBytes { + let content_start = self.range.context.start.to_offset(&self.buffer); + let bytes_start = content_start + range.start; + let bytes_end = content_start + cmp::min(range.end, self.text_summary.len); + let footer_height = if self.has_trailing_newline + && range.start <= self.text_summary.len + && range.end > self.text_summary.len + { + 1 + } else { + 0 + }; + let content_bytes = self.buffer.bytes_in_range(bytes_start..bytes_end); + + ExcerptBytes { + content_bytes, + footer_height, + } + } + + fn reversed_bytes_in_range(&self, range: Range) -> ExcerptBytes { + let content_start = self.range.context.start.to_offset(&self.buffer); + let bytes_start = content_start + range.start; + let bytes_end = content_start + cmp::min(range.end, self.text_summary.len); + let footer_height = if self.has_trailing_newline + && range.start <= self.text_summary.len + && range.end > self.text_summary.len + { + 1 + } else { + 0 + }; + let content_bytes = self.buffer.reversed_bytes_in_range(bytes_start..bytes_end); + + ExcerptBytes { + content_bytes, + footer_height, + } + } + + fn clip_anchor(&self, text_anchor: text::Anchor) -> text::Anchor { + if text_anchor + .cmp(&self.range.context.start, &self.buffer) + .is_lt() + { + self.range.context.start + } else if text_anchor + .cmp(&self.range.context.end, &self.buffer) + .is_gt() + { + self.range.context.end + } else { + text_anchor + } + } + + fn contains(&self, anchor: &Anchor) -> bool { + Some(self.buffer_id) == anchor.buffer_id + && self + .range + .context + .start + .cmp(&anchor.text_anchor, &self.buffer) + .is_le() + && self + .range + .context + .end + .cmp(&anchor.text_anchor, &self.buffer) + .is_ge() + } +} + +impl ExcerptId { + pub fn min() -> Self { + Self(0) + } + + pub fn max() -> Self { + Self(usize::MAX) + } + + pub fn to_proto(&self) -> u64 { + self.0 as _ + } + + pub fn from_proto(proto: u64) -> Self { + Self(proto as _) + } + + pub fn cmp(&self, other: &Self, snapshot: &MultiBufferSnapshot) -> cmp::Ordering { + let a = snapshot.excerpt_locator_for_id(*self); + let b = snapshot.excerpt_locator_for_id(*other); + a.cmp(&b).then_with(|| self.0.cmp(&other.0)) + } +} + +impl Into for ExcerptId { + fn into(self) -> usize { + self.0 + } +} + +impl fmt::Debug for Excerpt { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Excerpt") + .field("id", &self.id) + .field("locator", &self.locator) + .field("buffer_id", &self.buffer_id) + .field("range", &self.range) + .field("text_summary", &self.text_summary) + .field("has_trailing_newline", &self.has_trailing_newline) + .finish() + } +} + +impl sum_tree::Item for Excerpt { + type Summary = ExcerptSummary; + + fn summary(&self) -> Self::Summary { + let mut text = self.text_summary.clone(); + if self.has_trailing_newline { + text += TextSummary::from("\n"); + } + ExcerptSummary { + excerpt_id: self.id, + excerpt_locator: self.locator.clone(), + max_buffer_row: self.max_buffer_row, + text, + } + } +} + +impl sum_tree::Item for ExcerptIdMapping { + type Summary = ExcerptId; + + fn summary(&self) -> Self::Summary { + self.id + } +} + +impl sum_tree::KeyedItem for ExcerptIdMapping { + type Key = ExcerptId; + + fn key(&self) -> Self::Key { + self.id + } +} + +impl sum_tree::Summary for ExcerptId { + type Context = (); + + fn add_summary(&mut self, other: &Self, _: &()) { + *self = *other; + } +} + +impl sum_tree::Summary for ExcerptSummary { + type Context = (); + + fn add_summary(&mut self, summary: &Self, _: &()) { + debug_assert!(summary.excerpt_locator > self.excerpt_locator); + self.excerpt_locator = summary.excerpt_locator.clone(); + self.text.add_summary(&summary.text, &()); + self.max_buffer_row = cmp::max(self.max_buffer_row, summary.max_buffer_row); + } +} + +impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for TextSummary { + fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) { + *self += &summary.text; + } +} + +impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for usize { + fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) { + *self += summary.text.len; + } +} + +impl<'a> sum_tree::SeekTarget<'a, ExcerptSummary, ExcerptSummary> for usize { + fn cmp(&self, cursor_location: &ExcerptSummary, _: &()) -> cmp::Ordering { + Ord::cmp(self, &cursor_location.text.len) + } +} + +impl<'a> sum_tree::SeekTarget<'a, ExcerptSummary, Option<&'a Locator>> for Locator { + fn cmp(&self, cursor_location: &Option<&'a Locator>, _: &()) -> cmp::Ordering { + Ord::cmp(&Some(self), cursor_location) + } +} + +impl<'a> sum_tree::SeekTarget<'a, ExcerptSummary, ExcerptSummary> for Locator { + fn cmp(&self, cursor_location: &ExcerptSummary, _: &()) -> cmp::Ordering { + Ord::cmp(self, &cursor_location.excerpt_locator) + } +} + +impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for OffsetUtf16 { + fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) { + *self += summary.text.len_utf16; + } +} + +impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for Point { + fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) { + *self += summary.text.lines; + } +} + +impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for PointUtf16 { + fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) { + *self += summary.text.lines_utf16() + } +} + +impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for Option<&'a Locator> { + fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) { + *self = Some(&summary.excerpt_locator); + } +} + +impl<'a> sum_tree::Dimension<'a, ExcerptSummary> for Option { + fn add_summary(&mut self, summary: &'a ExcerptSummary, _: &()) { + *self = Some(summary.excerpt_id); + } +} + +impl<'a> MultiBufferRows<'a> { + pub fn seek(&mut self, row: u32) { + self.buffer_row_range = 0..0; + + self.excerpts + .seek_forward(&Point::new(row, 0), Bias::Right, &()); + if self.excerpts.item().is_none() { + self.excerpts.prev(&()); + + if self.excerpts.item().is_none() && row == 0 { + self.buffer_row_range = 0..1; + return; + } + } + + if let Some(excerpt) = self.excerpts.item() { + let overshoot = row - self.excerpts.start().row; + let excerpt_start = excerpt.range.context.start.to_point(&excerpt.buffer).row; + self.buffer_row_range.start = excerpt_start + overshoot; + self.buffer_row_range.end = excerpt_start + excerpt.text_summary.lines.row + 1; + } + } +} + +impl<'a> Iterator for MultiBufferRows<'a> { + type Item = Option; + + fn next(&mut self) -> Option { + loop { + if !self.buffer_row_range.is_empty() { + let row = Some(self.buffer_row_range.start); + self.buffer_row_range.start += 1; + return Some(row); + } + self.excerpts.item()?; + self.excerpts.next(&()); + let excerpt = self.excerpts.item()?; + self.buffer_row_range.start = excerpt.range.context.start.to_point(&excerpt.buffer).row; + self.buffer_row_range.end = + self.buffer_row_range.start + excerpt.text_summary.lines.row + 1; + } + } +} + +impl<'a> MultiBufferChunks<'a> { + pub fn offset(&self) -> usize { + self.range.start + } + + pub fn seek(&mut self, offset: usize) { + self.range.start = offset; + self.excerpts.seek(&offset, Bias::Right, &()); + if let Some(excerpt) = self.excerpts.item() { + self.excerpt_chunks = Some(excerpt.chunks_in_range( + self.range.start - self.excerpts.start()..self.range.end - self.excerpts.start(), + self.language_aware, + )); + } else { + self.excerpt_chunks = None; + } + } +} + +impl<'a> Iterator for MultiBufferChunks<'a> { + type Item = Chunk<'a>; + + fn next(&mut self) -> Option { + if self.range.is_empty() { + None + } else if let Some(chunk) = self.excerpt_chunks.as_mut()?.next() { + self.range.start += chunk.text.len(); + Some(chunk) + } else { + self.excerpts.next(&()); + let excerpt = self.excerpts.item()?; + self.excerpt_chunks = Some(excerpt.chunks_in_range( + 0..self.range.end - self.excerpts.start(), + self.language_aware, + )); + self.next() + } + } +} + +impl<'a> MultiBufferBytes<'a> { + fn consume(&mut self, len: usize) { + self.range.start += len; + self.chunk = &self.chunk[len..]; + + if !self.range.is_empty() && self.chunk.is_empty() { + if let Some(chunk) = self.excerpt_bytes.as_mut().and_then(|bytes| bytes.next()) { + self.chunk = chunk; + } else { + self.excerpts.next(&()); + if let Some(excerpt) = self.excerpts.item() { + let mut excerpt_bytes = + excerpt.bytes_in_range(0..self.range.end - self.excerpts.start()); + self.chunk = excerpt_bytes.next().unwrap(); + self.excerpt_bytes = Some(excerpt_bytes); + } + } + } + } +} + +impl<'a> Iterator for MultiBufferBytes<'a> { + type Item = &'a [u8]; + + fn next(&mut self) -> Option { + let chunk = self.chunk; + if chunk.is_empty() { + None + } else { + self.consume(chunk.len()); + Some(chunk) + } + } +} + +impl<'a> io::Read for MultiBufferBytes<'a> { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + let len = cmp::min(buf.len(), self.chunk.len()); + buf[..len].copy_from_slice(&self.chunk[..len]); + if len > 0 { + self.consume(len); + } + Ok(len) + } +} + +impl<'a> ReversedMultiBufferBytes<'a> { + fn consume(&mut self, len: usize) { + self.range.end -= len; + self.chunk = &self.chunk[..self.chunk.len() - len]; + + if !self.range.is_empty() && self.chunk.is_empty() { + if let Some(chunk) = self.excerpt_bytes.as_mut().and_then(|bytes| bytes.next()) { + self.chunk = chunk; + } else { + self.excerpts.next(&()); + if let Some(excerpt) = self.excerpts.item() { + let mut excerpt_bytes = + excerpt.bytes_in_range(0..self.range.end - self.excerpts.start()); + self.chunk = excerpt_bytes.next().unwrap(); + self.excerpt_bytes = Some(excerpt_bytes); + } + } + } + } +} + +impl<'a> io::Read for ReversedMultiBufferBytes<'a> { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + let len = cmp::min(buf.len(), self.chunk.len()); + buf[..len].copy_from_slice(&self.chunk[..len]); + buf[..len].reverse(); + if len > 0 { + self.consume(len); + } + Ok(len) + } +} +impl<'a> Iterator for ExcerptBytes<'a> { + type Item = &'a [u8]; + + fn next(&mut self) -> Option { + if let Some(chunk) = self.content_bytes.next() { + if !chunk.is_empty() { + return Some(chunk); + } + } + + if self.footer_height > 0 { + let result = &NEWLINES[..self.footer_height]; + self.footer_height = 0; + return Some(result); + } + + None + } +} + +impl<'a> Iterator for ExcerptChunks<'a> { + type Item = Chunk<'a>; + + fn next(&mut self) -> Option { + if let Some(chunk) = self.content_chunks.next() { + return Some(chunk); + } + + if self.footer_height > 0 { + let text = unsafe { str::from_utf8_unchecked(&NEWLINES[..self.footer_height]) }; + self.footer_height = 0; + return Some(Chunk { + text, + ..Default::default() + }); + } + + None + } +} + +impl ToOffset for Point { + fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize { + snapshot.point_to_offset(*self) + } +} + +impl ToOffset for usize { + fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize { + assert!(*self <= snapshot.len(), "offset is out of range"); + *self + } +} + +impl ToOffset for OffsetUtf16 { + fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize { + snapshot.offset_utf16_to_offset(*self) + } +} + +impl ToOffset for PointUtf16 { + fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize { + snapshot.point_utf16_to_offset(*self) + } +} + +impl ToOffsetUtf16 for OffsetUtf16 { + fn to_offset_utf16(&self, _snapshot: &MultiBufferSnapshot) -> OffsetUtf16 { + *self + } +} + +impl ToOffsetUtf16 for usize { + fn to_offset_utf16(&self, snapshot: &MultiBufferSnapshot) -> OffsetUtf16 { + snapshot.offset_to_offset_utf16(*self) + } +} + +impl ToPoint for usize { + fn to_point<'a>(&self, snapshot: &MultiBufferSnapshot) -> Point { + snapshot.offset_to_point(*self) + } +} + +impl ToPoint for Point { + fn to_point<'a>(&self, _: &MultiBufferSnapshot) -> Point { + *self + } +} + +impl ToPointUtf16 for usize { + fn to_point_utf16<'a>(&self, snapshot: &MultiBufferSnapshot) -> PointUtf16 { + snapshot.offset_to_point_utf16(*self) + } +} + +impl ToPointUtf16 for Point { + fn to_point_utf16<'a>(&self, snapshot: &MultiBufferSnapshot) -> PointUtf16 { + snapshot.point_to_point_utf16(*self) + } +} + +impl ToPointUtf16 for PointUtf16 { + fn to_point_utf16<'a>(&self, _: &MultiBufferSnapshot) -> PointUtf16 { + *self + } +} + +fn build_excerpt_ranges( + buffer: &BufferSnapshot, + ranges: &[Range], + context_line_count: u32, +) -> (Vec>, Vec) +where + T: text::ToPoint, +{ + let max_point = buffer.max_point(); + let mut range_counts = Vec::new(); + let mut excerpt_ranges = Vec::new(); + let mut range_iter = ranges + .iter() + .map(|range| range.start.to_point(buffer)..range.end.to_point(buffer)) + .peekable(); + while let Some(range) = range_iter.next() { + let excerpt_start = Point::new(range.start.row.saturating_sub(context_line_count), 0); + let mut excerpt_end = Point::new(range.end.row + 1 + context_line_count, 0).min(max_point); + let mut ranges_in_excerpt = 1; + + while let Some(next_range) = range_iter.peek() { + if next_range.start.row <= excerpt_end.row + context_line_count { + excerpt_end = + Point::new(next_range.end.row + 1 + context_line_count, 0).min(max_point); + ranges_in_excerpt += 1; + range_iter.next(); + } else { + break; + } + } + + excerpt_ranges.push(ExcerptRange { + context: excerpt_start..excerpt_end, + primary: Some(range), + }); + range_counts.push(ranges_in_excerpt); + } + + (excerpt_ranges, range_counts) +} + +#[cfg(test)] +mod tests { + use super::*; + use futures::StreamExt; + use gpui2::{AppContext, Context, TestAppContext}; + use language2::{Buffer, Rope}; + use parking_lot::RwLock; + use rand::prelude::*; + use settings2::SettingsStore; + use std::env; + use util::test::sample_text; + + #[gpui2::test] + fn test_singleton(cx: &mut AppContext) { + let buffer = + cx.build_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), sample_text(6, 6, 'a'))); + let multibuffer = cx.build_model(|cx| MultiBuffer::singleton(buffer.clone(), cx)); + + let snapshot = multibuffer.read(cx).snapshot(cx); + assert_eq!(snapshot.text(), buffer.read(cx).text()); + + assert_eq!( + snapshot.buffer_rows(0).collect::>(), + (0..buffer.read(cx).row_count()) + .map(Some) + .collect::>() + ); + + buffer.update(cx, |buffer, cx| buffer.edit([(1..3, "XXX\n")], None, cx)); + let snapshot = multibuffer.read(cx).snapshot(cx); + + assert_eq!(snapshot.text(), buffer.read(cx).text()); + assert_eq!( + snapshot.buffer_rows(0).collect::>(), + (0..buffer.read(cx).row_count()) + .map(Some) + .collect::>() + ); + } + + #[gpui2::test] + fn test_remote(cx: &mut AppContext) { + let host_buffer = cx.build_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), "a")); + let guest_buffer = cx.build_model(|cx| { + let state = host_buffer.read(cx).to_proto(); + let ops = cx + .executor() + .block(host_buffer.read(cx).serialize_ops(None, cx)); + let mut buffer = Buffer::from_proto(1, state, None).unwrap(); + buffer + .apply_ops( + ops.into_iter() + .map(|op| language2::proto::deserialize_operation(op).unwrap()), + cx, + ) + .unwrap(); + buffer + }); + let multibuffer = cx.build_model(|cx| MultiBuffer::singleton(guest_buffer.clone(), cx)); + let snapshot = multibuffer.read(cx).snapshot(cx); + assert_eq!(snapshot.text(), "a"); + + guest_buffer.update(cx, |buffer, cx| buffer.edit([(1..1, "b")], None, cx)); + let snapshot = multibuffer.read(cx).snapshot(cx); + assert_eq!(snapshot.text(), "ab"); + + guest_buffer.update(cx, |buffer, cx| buffer.edit([(2..2, "c")], None, cx)); + let snapshot = multibuffer.read(cx).snapshot(cx); + assert_eq!(snapshot.text(), "abc"); + } + + #[gpui2::test] + fn test_excerpt_boundaries_and_clipping(cx: &mut AppContext) { + let buffer_1 = + cx.build_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), sample_text(6, 6, 'a'))); + let buffer_2 = + cx.build_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), sample_text(6, 6, 'g'))); + let multibuffer = cx.build_model(|_| MultiBuffer::new(0)); + + let events = Arc::new(RwLock::new(Vec::::new())); + multibuffer.update(cx, |_, cx| { + let events = events.clone(); + cx.subscribe(&multibuffer, move |_, _, event, _| { + if let Event::Edited { .. } = event { + events.write().push(event.clone()) + } + }) + .detach(); + }); + + let subscription = multibuffer.update(cx, |multibuffer, cx| { + let subscription = multibuffer.subscribe(); + multibuffer.push_excerpts( + buffer_1.clone(), + [ExcerptRange { + context: Point::new(1, 2)..Point::new(2, 5), + primary: None, + }], + cx, + ); + assert_eq!( + subscription.consume().into_inner(), + [Edit { + old: 0..0, + new: 0..10 + }] + ); + + multibuffer.push_excerpts( + buffer_1.clone(), + [ExcerptRange { + context: Point::new(3, 3)..Point::new(4, 4), + primary: None, + }], + cx, + ); + multibuffer.push_excerpts( + buffer_2.clone(), + [ExcerptRange { + context: Point::new(3, 1)..Point::new(3, 3), + primary: None, + }], + cx, + ); + assert_eq!( + subscription.consume().into_inner(), + [Edit { + old: 10..10, + new: 10..22 + }] + ); + + subscription + }); + + // Adding excerpts emits an edited event. + assert_eq!( + events.read().as_slice(), + &[ + Event::Edited { + sigleton_buffer_edited: false + }, + Event::Edited { + sigleton_buffer_edited: false + }, + Event::Edited { + sigleton_buffer_edited: false + } + ] + ); + + let snapshot = multibuffer.read(cx).snapshot(cx); + assert_eq!( + snapshot.text(), + concat!( + "bbbb\n", // Preserve newlines + "ccccc\n", // + "ddd\n", // + "eeee\n", // + "jj" // + ) + ); + assert_eq!( + snapshot.buffer_rows(0).collect::>(), + [Some(1), Some(2), Some(3), Some(4), Some(3)] + ); + assert_eq!( + snapshot.buffer_rows(2).collect::>(), + [Some(3), Some(4), Some(3)] + ); + assert_eq!(snapshot.buffer_rows(4).collect::>(), [Some(3)]); + assert_eq!(snapshot.buffer_rows(5).collect::>(), []); + + assert_eq!( + boundaries_in_range(Point::new(0, 0)..Point::new(4, 2), &snapshot), + &[ + (0, "bbbb\nccccc".to_string(), true), + (2, "ddd\neeee".to_string(), false), + (4, "jj".to_string(), true), + ] + ); + assert_eq!( + boundaries_in_range(Point::new(0, 0)..Point::new(2, 0), &snapshot), + &[(0, "bbbb\nccccc".to_string(), true)] + ); + assert_eq!( + boundaries_in_range(Point::new(1, 0)..Point::new(1, 5), &snapshot), + &[] + ); + assert_eq!( + boundaries_in_range(Point::new(1, 0)..Point::new(2, 0), &snapshot), + &[] + ); + assert_eq!( + boundaries_in_range(Point::new(1, 0)..Point::new(4, 0), &snapshot), + &[(2, "ddd\neeee".to_string(), false)] + ); + assert_eq!( + boundaries_in_range(Point::new(1, 0)..Point::new(4, 0), &snapshot), + &[(2, "ddd\neeee".to_string(), false)] + ); + assert_eq!( + boundaries_in_range(Point::new(2, 0)..Point::new(3, 0), &snapshot), + &[(2, "ddd\neeee".to_string(), false)] + ); + assert_eq!( + boundaries_in_range(Point::new(4, 0)..Point::new(4, 2), &snapshot), + &[(4, "jj".to_string(), true)] + ); + assert_eq!( + boundaries_in_range(Point::new(4, 2)..Point::new(4, 2), &snapshot), + &[] + ); + + buffer_1.update(cx, |buffer, cx| { + let text = "\n"; + buffer.edit( + [ + (Point::new(0, 0)..Point::new(0, 0), text), + (Point::new(2, 1)..Point::new(2, 3), text), + ], + None, + cx, + ); + }); + + let snapshot = multibuffer.read(cx).snapshot(cx); + assert_eq!( + snapshot.text(), + concat!( + "bbbb\n", // Preserve newlines + "c\n", // + "cc\n", // + "ddd\n", // + "eeee\n", // + "jj" // + ) + ); + + assert_eq!( + subscription.consume().into_inner(), + [Edit { + old: 6..8, + new: 6..7 + }] + ); + + let snapshot = multibuffer.read(cx).snapshot(cx); + assert_eq!( + snapshot.clip_point(Point::new(0, 5), Bias::Left), + Point::new(0, 4) + ); + assert_eq!( + snapshot.clip_point(Point::new(0, 5), Bias::Right), + Point::new(0, 4) + ); + assert_eq!( + snapshot.clip_point(Point::new(5, 1), Bias::Right), + Point::new(5, 1) + ); + assert_eq!( + snapshot.clip_point(Point::new(5, 2), Bias::Right), + Point::new(5, 2) + ); + assert_eq!( + snapshot.clip_point(Point::new(5, 3), Bias::Right), + Point::new(5, 2) + ); + + let snapshot = multibuffer.update(cx, |multibuffer, cx| { + let (buffer_2_excerpt_id, _) = + multibuffer.excerpts_for_buffer(&buffer_2, cx)[0].clone(); + multibuffer.remove_excerpts([buffer_2_excerpt_id], cx); + multibuffer.snapshot(cx) + }); + + assert_eq!( + snapshot.text(), + concat!( + "bbbb\n", // Preserve newlines + "c\n", // + "cc\n", // + "ddd\n", // + "eeee", // + ) + ); + + fn boundaries_in_range( + range: Range, + snapshot: &MultiBufferSnapshot, + ) -> Vec<(u32, String, bool)> { + snapshot + .excerpt_boundaries_in_range(range) + .map(|boundary| { + ( + boundary.row, + boundary + .buffer + .text_for_range(boundary.range.context) + .collect::(), + boundary.starts_new_buffer, + ) + }) + .collect::>() + } + } + + #[gpui2::test] + fn test_excerpt_events(cx: &mut AppContext) { + let buffer_1 = + cx.build_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), sample_text(10, 3, 'a'))); + let buffer_2 = + cx.build_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), sample_text(10, 3, 'm'))); + + let leader_multibuffer = cx.build_model(|_| MultiBuffer::new(0)); + let follower_multibuffer = cx.build_model(|_| MultiBuffer::new(0)); + let follower_edit_event_count = Arc::new(RwLock::new(0)); + + follower_multibuffer.update(cx, |_, cx| { + let follower_edit_event_count = follower_edit_event_count.clone(); + cx.subscribe( + &leader_multibuffer, + move |follower, _, event, cx| match event.clone() { + Event::ExcerptsAdded { + buffer, + predecessor, + excerpts, + } => follower.insert_excerpts_with_ids_after(predecessor, buffer, excerpts, cx), + Event::ExcerptsRemoved { ids } => follower.remove_excerpts(ids, cx), + Event::Edited { .. } => { + *follower_edit_event_count.write() += 1; + } + _ => {} + }, + ) + .detach(); + }); + + leader_multibuffer.update(cx, |leader, cx| { + leader.push_excerpts( + buffer_1.clone(), + [ + ExcerptRange { + context: 0..8, + primary: None, + }, + ExcerptRange { + context: 12..16, + primary: None, + }, + ], + cx, + ); + leader.insert_excerpts_after( + leader.excerpt_ids()[0], + buffer_2.clone(), + [ + ExcerptRange { + context: 0..5, + primary: None, + }, + ExcerptRange { + context: 10..15, + primary: None, + }, + ], + cx, + ) + }); + assert_eq!( + leader_multibuffer.read(cx).snapshot(cx).text(), + follower_multibuffer.read(cx).snapshot(cx).text(), + ); + assert_eq!(*follower_edit_event_count.read(), 2); + + leader_multibuffer.update(cx, |leader, cx| { + let excerpt_ids = leader.excerpt_ids(); + leader.remove_excerpts([excerpt_ids[1], excerpt_ids[3]], cx); + }); + assert_eq!( + leader_multibuffer.read(cx).snapshot(cx).text(), + follower_multibuffer.read(cx).snapshot(cx).text(), + ); + assert_eq!(*follower_edit_event_count.read(), 3); + + // Removing an empty set of excerpts is a noop. + leader_multibuffer.update(cx, |leader, cx| { + leader.remove_excerpts([], cx); + }); + assert_eq!( + leader_multibuffer.read(cx).snapshot(cx).text(), + follower_multibuffer.read(cx).snapshot(cx).text(), + ); + assert_eq!(*follower_edit_event_count.read(), 3); + + // Adding an empty set of excerpts is a noop. + leader_multibuffer.update(cx, |leader, cx| { + leader.push_excerpts::(buffer_2.clone(), [], cx); + }); + assert_eq!( + leader_multibuffer.read(cx).snapshot(cx).text(), + follower_multibuffer.read(cx).snapshot(cx).text(), + ); + assert_eq!(*follower_edit_event_count.read(), 3); + + leader_multibuffer.update(cx, |leader, cx| { + leader.clear(cx); + }); + assert_eq!( + leader_multibuffer.read(cx).snapshot(cx).text(), + follower_multibuffer.read(cx).snapshot(cx).text(), + ); + assert_eq!(*follower_edit_event_count.read(), 4); + } + + #[gpui2::test] + fn test_push_excerpts_with_context_lines(cx: &mut AppContext) { + let buffer = + cx.build_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), sample_text(20, 3, 'a'))); + let multibuffer = cx.build_model(|_| MultiBuffer::new(0)); + let anchor_ranges = multibuffer.update(cx, |multibuffer, cx| { + multibuffer.push_excerpts_with_context_lines( + buffer.clone(), + vec![ + Point::new(3, 2)..Point::new(4, 2), + Point::new(7, 1)..Point::new(7, 3), + Point::new(15, 0)..Point::new(15, 0), + ], + 2, + cx, + ) + }); + + let snapshot = multibuffer.read(cx).snapshot(cx); + assert_eq!( + snapshot.text(), + "bbb\nccc\nddd\neee\nfff\nggg\nhhh\niii\njjj\n\nnnn\nooo\nppp\nqqq\nrrr\n" + ); + + assert_eq!( + anchor_ranges + .iter() + .map(|range| range.to_point(&snapshot)) + .collect::>(), + vec![ + Point::new(2, 2)..Point::new(3, 2), + Point::new(6, 1)..Point::new(6, 3), + Point::new(12, 0)..Point::new(12, 0) + ] + ); + } + + #[gpui2::test] + async fn test_stream_excerpts_with_context_lines(cx: &mut TestAppContext) { + let buffer = + cx.build_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), sample_text(20, 3, 'a'))); + let multibuffer = cx.build_model(|_| MultiBuffer::new(0)); + let anchor_ranges = multibuffer.update(cx, |multibuffer, cx| { + let snapshot = buffer.read(cx); + let ranges = vec![ + snapshot.anchor_before(Point::new(3, 2))..snapshot.anchor_before(Point::new(4, 2)), + snapshot.anchor_before(Point::new(7, 1))..snapshot.anchor_before(Point::new(7, 3)), + snapshot.anchor_before(Point::new(15, 0)) + ..snapshot.anchor_before(Point::new(15, 0)), + ]; + multibuffer.stream_excerpts_with_context_lines(buffer.clone(), ranges, 2, cx) + }); + + let anchor_ranges = anchor_ranges.collect::>().await; + + let snapshot = multibuffer.update(cx, |multibuffer, cx| multibuffer.snapshot(cx)); + assert_eq!( + snapshot.text(), + "bbb\nccc\nddd\neee\nfff\nggg\nhhh\niii\njjj\n\nnnn\nooo\nppp\nqqq\nrrr\n" + ); + + assert_eq!( + anchor_ranges + .iter() + .map(|range| range.to_point(&snapshot)) + .collect::>(), + vec![ + Point::new(2, 2)..Point::new(3, 2), + Point::new(6, 1)..Point::new(6, 3), + Point::new(12, 0)..Point::new(12, 0) + ] + ); + } + + #[gpui2::test] + fn test_empty_multibuffer(cx: &mut AppContext) { + let multibuffer = cx.build_model(|_| MultiBuffer::new(0)); + + let snapshot = multibuffer.read(cx).snapshot(cx); + assert_eq!(snapshot.text(), ""); + assert_eq!(snapshot.buffer_rows(0).collect::>(), &[Some(0)]); + assert_eq!(snapshot.buffer_rows(1).collect::>(), &[]); + } + + #[gpui2::test] + fn test_singleton_multibuffer_anchors(cx: &mut AppContext) { + let buffer = cx.build_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), "abcd")); + let multibuffer = cx.build_model(|cx| MultiBuffer::singleton(buffer.clone(), cx)); + let old_snapshot = multibuffer.read(cx).snapshot(cx); + buffer.update(cx, |buffer, cx| { + buffer.edit([(0..0, "X")], None, cx); + buffer.edit([(5..5, "Y")], None, cx); + }); + let new_snapshot = multibuffer.read(cx).snapshot(cx); + + assert_eq!(old_snapshot.text(), "abcd"); + assert_eq!(new_snapshot.text(), "XabcdY"); + + assert_eq!(old_snapshot.anchor_before(0).to_offset(&new_snapshot), 0); + assert_eq!(old_snapshot.anchor_after(0).to_offset(&new_snapshot), 1); + assert_eq!(old_snapshot.anchor_before(4).to_offset(&new_snapshot), 5); + assert_eq!(old_snapshot.anchor_after(4).to_offset(&new_snapshot), 6); + } + + #[gpui2::test] + fn test_multibuffer_anchors(cx: &mut AppContext) { + let buffer_1 = cx.build_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), "abcd")); + let buffer_2 = cx.build_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), "efghi")); + let multibuffer = cx.build_model(|cx| { + let mut multibuffer = MultiBuffer::new(0); + multibuffer.push_excerpts( + buffer_1.clone(), + [ExcerptRange { + context: 0..4, + primary: None, + }], + cx, + ); + multibuffer.push_excerpts( + buffer_2.clone(), + [ExcerptRange { + context: 0..5, + primary: None, + }], + cx, + ); + multibuffer + }); + let old_snapshot = multibuffer.read(cx).snapshot(cx); + + assert_eq!(old_snapshot.anchor_before(0).to_offset(&old_snapshot), 0); + assert_eq!(old_snapshot.anchor_after(0).to_offset(&old_snapshot), 0); + assert_eq!(Anchor::min().to_offset(&old_snapshot), 0); + assert_eq!(Anchor::min().to_offset(&old_snapshot), 0); + assert_eq!(Anchor::max().to_offset(&old_snapshot), 10); + assert_eq!(Anchor::max().to_offset(&old_snapshot), 10); + + buffer_1.update(cx, |buffer, cx| { + buffer.edit([(0..0, "W")], None, cx); + buffer.edit([(5..5, "X")], None, cx); + }); + buffer_2.update(cx, |buffer, cx| { + buffer.edit([(0..0, "Y")], None, cx); + buffer.edit([(6..6, "Z")], None, cx); + }); + let new_snapshot = multibuffer.read(cx).snapshot(cx); + + assert_eq!(old_snapshot.text(), "abcd\nefghi"); + assert_eq!(new_snapshot.text(), "WabcdX\nYefghiZ"); + + assert_eq!(old_snapshot.anchor_before(0).to_offset(&new_snapshot), 0); + assert_eq!(old_snapshot.anchor_after(0).to_offset(&new_snapshot), 1); + assert_eq!(old_snapshot.anchor_before(1).to_offset(&new_snapshot), 2); + assert_eq!(old_snapshot.anchor_after(1).to_offset(&new_snapshot), 2); + assert_eq!(old_snapshot.anchor_before(2).to_offset(&new_snapshot), 3); + assert_eq!(old_snapshot.anchor_after(2).to_offset(&new_snapshot), 3); + assert_eq!(old_snapshot.anchor_before(5).to_offset(&new_snapshot), 7); + assert_eq!(old_snapshot.anchor_after(5).to_offset(&new_snapshot), 8); + assert_eq!(old_snapshot.anchor_before(10).to_offset(&new_snapshot), 13); + assert_eq!(old_snapshot.anchor_after(10).to_offset(&new_snapshot), 14); + } + + #[gpui2::test] + fn test_resolving_anchors_after_replacing_their_excerpts(cx: &mut AppContext) { + let buffer_1 = cx.build_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), "abcd")); + let buffer_2 = + cx.build_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), "ABCDEFGHIJKLMNOP")); + let multibuffer = cx.build_model(|_| MultiBuffer::new(0)); + + // Create an insertion id in buffer 1 that doesn't exist in buffer 2. + // Add an excerpt from buffer 1 that spans this new insertion. + buffer_1.update(cx, |buffer, cx| buffer.edit([(4..4, "123")], None, cx)); + let excerpt_id_1 = multibuffer.update(cx, |multibuffer, cx| { + multibuffer + .push_excerpts( + buffer_1.clone(), + [ExcerptRange { + context: 0..7, + primary: None, + }], + cx, + ) + .pop() + .unwrap() + }); + + let snapshot_1 = multibuffer.read(cx).snapshot(cx); + assert_eq!(snapshot_1.text(), "abcd123"); + + // Replace the buffer 1 excerpt with new excerpts from buffer 2. + let (excerpt_id_2, excerpt_id_3) = multibuffer.update(cx, |multibuffer, cx| { + multibuffer.remove_excerpts([excerpt_id_1], cx); + let mut ids = multibuffer + .push_excerpts( + buffer_2.clone(), + [ + ExcerptRange { + context: 0..4, + primary: None, + }, + ExcerptRange { + context: 6..10, + primary: None, + }, + ExcerptRange { + context: 12..16, + primary: None, + }, + ], + cx, + ) + .into_iter(); + (ids.next().unwrap(), ids.next().unwrap()) + }); + let snapshot_2 = multibuffer.read(cx).snapshot(cx); + assert_eq!(snapshot_2.text(), "ABCD\nGHIJ\nMNOP"); + + // The old excerpt id doesn't get reused. + assert_ne!(excerpt_id_2, excerpt_id_1); + + // Resolve some anchors from the previous snapshot in the new snapshot. + // The current excerpts are from a different buffer, so we don't attempt to + // resolve the old text anchor in the new buffer. + assert_eq!( + snapshot_2.summary_for_anchor::(&snapshot_1.anchor_before(2)), + 0 + ); + assert_eq!( + snapshot_2.summaries_for_anchors::(&[ + snapshot_1.anchor_before(2), + snapshot_1.anchor_after(3) + ]), + vec![0, 0] + ); + + // Refresh anchors from the old snapshot. The return value indicates that both + // anchors lost their original excerpt. + let refresh = + snapshot_2.refresh_anchors(&[snapshot_1.anchor_before(2), snapshot_1.anchor_after(3)]); + assert_eq!( + refresh, + &[ + (0, snapshot_2.anchor_before(0), false), + (1, snapshot_2.anchor_after(0), false), + ] + ); + + // Replace the middle excerpt with a smaller excerpt in buffer 2, + // that intersects the old excerpt. + let excerpt_id_5 = multibuffer.update(cx, |multibuffer, cx| { + multibuffer.remove_excerpts([excerpt_id_3], cx); + multibuffer + .insert_excerpts_after( + excerpt_id_2, + buffer_2.clone(), + [ExcerptRange { + context: 5..8, + primary: None, + }], + cx, + ) + .pop() + .unwrap() + }); + + let snapshot_3 = multibuffer.read(cx).snapshot(cx); + assert_eq!(snapshot_3.text(), "ABCD\nFGH\nMNOP"); + assert_ne!(excerpt_id_5, excerpt_id_3); + + // Resolve some anchors from the previous snapshot in the new snapshot. + // The third anchor can't be resolved, since its excerpt has been removed, + // so it resolves to the same position as its predecessor. + let anchors = [ + snapshot_2.anchor_before(0), + snapshot_2.anchor_after(2), + snapshot_2.anchor_after(6), + snapshot_2.anchor_after(14), + ]; + assert_eq!( + snapshot_3.summaries_for_anchors::(&anchors), + &[0, 2, 9, 13] + ); + + let new_anchors = snapshot_3.refresh_anchors(&anchors); + assert_eq!( + new_anchors.iter().map(|a| (a.0, a.2)).collect::>(), + &[(0, true), (1, true), (2, true), (3, true)] + ); + assert_eq!( + snapshot_3.summaries_for_anchors::(new_anchors.iter().map(|a| &a.1)), + &[0, 2, 7, 13] + ); + } + + #[gpui2::test(iterations = 100)] + fn test_random_multibuffer(cx: &mut AppContext, mut rng: StdRng) { + let operations = env::var("OPERATIONS") + .map(|i| i.parse().expect("invalid `OPERATIONS` variable")) + .unwrap_or(10); + + let mut buffers: Vec> = Vec::new(); + let multibuffer = cx.build_model(|_| MultiBuffer::new(0)); + let mut excerpt_ids = Vec::::new(); + let mut expected_excerpts = Vec::<(Model, Range)>::new(); + let mut anchors = Vec::new(); + let mut old_versions = Vec::new(); + + for _ in 0..operations { + match rng.gen_range(0..100) { + 0..=19 if !buffers.is_empty() => { + let buffer = buffers.choose(&mut rng).unwrap(); + buffer.update(cx, |buf, cx| buf.randomly_edit(&mut rng, 5, cx)); + } + 20..=29 if !expected_excerpts.is_empty() => { + let mut ids_to_remove = vec![]; + for _ in 0..rng.gen_range(1..=3) { + if expected_excerpts.is_empty() { + break; + } + + let ix = rng.gen_range(0..expected_excerpts.len()); + ids_to_remove.push(excerpt_ids.remove(ix)); + let (buffer, range) = expected_excerpts.remove(ix); + let buffer = buffer.read(cx); + log::info!( + "Removing excerpt {}: {:?}", + ix, + buffer + .text_for_range(range.to_offset(buffer)) + .collect::(), + ); + } + let snapshot = multibuffer.read(cx).read(cx); + ids_to_remove.sort_unstable_by(|a, b| a.cmp(&b, &snapshot)); + drop(snapshot); + multibuffer.update(cx, |multibuffer, cx| { + multibuffer.remove_excerpts(ids_to_remove, cx) + }); + } + 30..=39 if !expected_excerpts.is_empty() => { + let multibuffer = multibuffer.read(cx).read(cx); + let offset = + multibuffer.clip_offset(rng.gen_range(0..=multibuffer.len()), Bias::Left); + let bias = if rng.gen() { Bias::Left } else { Bias::Right }; + log::info!("Creating anchor at {} with bias {:?}", offset, bias); + anchors.push(multibuffer.anchor_at(offset, bias)); + anchors.sort_by(|a, b| a.cmp(b, &multibuffer)); + } + 40..=44 if !anchors.is_empty() => { + let multibuffer = multibuffer.read(cx).read(cx); + let prev_len = anchors.len(); + anchors = multibuffer + .refresh_anchors(&anchors) + .into_iter() + .map(|a| a.1) + .collect(); + + // Ensure the newly-refreshed anchors point to a valid excerpt and don't + // overshoot its boundaries. + assert_eq!(anchors.len(), prev_len); + for anchor in &anchors { + if anchor.excerpt_id == ExcerptId::min() + || anchor.excerpt_id == ExcerptId::max() + { + continue; + } + + let excerpt = multibuffer.excerpt(anchor.excerpt_id).unwrap(); + assert_eq!(excerpt.id, anchor.excerpt_id); + assert!(excerpt.contains(anchor)); + } + } + _ => { + let buffer_handle = if buffers.is_empty() || rng.gen_bool(0.4) { + let base_text = util::RandomCharIter::new(&mut rng) + .take(10) + .collect::(); + buffers.push( + cx.build_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), base_text)), + ); + buffers.last().unwrap() + } else { + buffers.choose(&mut rng).unwrap() + }; + + let buffer = buffer_handle.read(cx); + let end_ix = buffer.clip_offset(rng.gen_range(0..=buffer.len()), Bias::Right); + let start_ix = buffer.clip_offset(rng.gen_range(0..=end_ix), Bias::Left); + let anchor_range = buffer.anchor_before(start_ix)..buffer.anchor_after(end_ix); + let prev_excerpt_ix = rng.gen_range(0..=expected_excerpts.len()); + let prev_excerpt_id = excerpt_ids + .get(prev_excerpt_ix) + .cloned() + .unwrap_or_else(ExcerptId::max); + let excerpt_ix = (prev_excerpt_ix + 1).min(expected_excerpts.len()); + + log::info!( + "Inserting excerpt at {} of {} for buffer {}: {:?}[{:?}] = {:?}", + excerpt_ix, + expected_excerpts.len(), + buffer_handle.read(cx).remote_id(), + buffer.text(), + start_ix..end_ix, + &buffer.text()[start_ix..end_ix] + ); + + let excerpt_id = multibuffer.update(cx, |multibuffer, cx| { + multibuffer + .insert_excerpts_after( + prev_excerpt_id, + buffer_handle.clone(), + [ExcerptRange { + context: start_ix..end_ix, + primary: None, + }], + cx, + ) + .pop() + .unwrap() + }); + + excerpt_ids.insert(excerpt_ix, excerpt_id); + expected_excerpts.insert(excerpt_ix, (buffer_handle.clone(), anchor_range)); + } + } + + if rng.gen_bool(0.3) { + multibuffer.update(cx, |multibuffer, cx| { + old_versions.push((multibuffer.snapshot(cx), multibuffer.subscribe())); + }) + } + + let snapshot = multibuffer.read(cx).snapshot(cx); + + let mut excerpt_starts = Vec::new(); + let mut expected_text = String::new(); + let mut expected_buffer_rows = Vec::new(); + for (buffer, range) in &expected_excerpts { + let buffer = buffer.read(cx); + let buffer_range = range.to_offset(buffer); + + excerpt_starts.push(TextSummary::from(expected_text.as_str())); + expected_text.extend(buffer.text_for_range(buffer_range.clone())); + expected_text.push('\n'); + + let buffer_row_range = buffer.offset_to_point(buffer_range.start).row + ..=buffer.offset_to_point(buffer_range.end).row; + for row in buffer_row_range { + expected_buffer_rows.push(Some(row)); + } + } + // Remove final trailing newline. + if !expected_excerpts.is_empty() { + expected_text.pop(); + } + + // Always report one buffer row + if expected_buffer_rows.is_empty() { + expected_buffer_rows.push(Some(0)); + } + + assert_eq!(snapshot.text(), expected_text); + log::info!("MultiBuffer text: {:?}", expected_text); + + assert_eq!( + snapshot.buffer_rows(0).collect::>(), + expected_buffer_rows, + ); + + for _ in 0..5 { + let start_row = rng.gen_range(0..=expected_buffer_rows.len()); + assert_eq!( + snapshot.buffer_rows(start_row as u32).collect::>(), + &expected_buffer_rows[start_row..], + "buffer_rows({})", + start_row + ); + } + + assert_eq!( + snapshot.max_buffer_row(), + expected_buffer_rows.into_iter().flatten().max().unwrap() + ); + + let mut excerpt_starts = excerpt_starts.into_iter(); + for (buffer, range) in &expected_excerpts { + let buffer = buffer.read(cx); + let buffer_id = buffer.remote_id(); + let buffer_range = range.to_offset(buffer); + let buffer_start_point = buffer.offset_to_point(buffer_range.start); + let buffer_start_point_utf16 = + buffer.text_summary_for_range::(0..buffer_range.start); + + let excerpt_start = excerpt_starts.next().unwrap(); + let mut offset = excerpt_start.len; + let mut buffer_offset = buffer_range.start; + let mut point = excerpt_start.lines; + let mut buffer_point = buffer_start_point; + let mut point_utf16 = excerpt_start.lines_utf16(); + let mut buffer_point_utf16 = buffer_start_point_utf16; + for ch in buffer + .snapshot() + .chunks(buffer_range.clone(), false) + .flat_map(|c| c.text.chars()) + { + for _ in 0..ch.len_utf8() { + let left_offset = snapshot.clip_offset(offset, Bias::Left); + let right_offset = snapshot.clip_offset(offset, Bias::Right); + let buffer_left_offset = buffer.clip_offset(buffer_offset, Bias::Left); + let buffer_right_offset = buffer.clip_offset(buffer_offset, Bias::Right); + assert_eq!( + left_offset, + excerpt_start.len + (buffer_left_offset - buffer_range.start), + "clip_offset({:?}, Left). buffer: {:?}, buffer offset: {:?}", + offset, + buffer_id, + buffer_offset, + ); + assert_eq!( + right_offset, + excerpt_start.len + (buffer_right_offset - buffer_range.start), + "clip_offset({:?}, Right). buffer: {:?}, buffer offset: {:?}", + offset, + buffer_id, + buffer_offset, + ); + + let left_point = snapshot.clip_point(point, Bias::Left); + let right_point = snapshot.clip_point(point, Bias::Right); + let buffer_left_point = buffer.clip_point(buffer_point, Bias::Left); + let buffer_right_point = buffer.clip_point(buffer_point, Bias::Right); + assert_eq!( + left_point, + excerpt_start.lines + (buffer_left_point - buffer_start_point), + "clip_point({:?}, Left). buffer: {:?}, buffer point: {:?}", + point, + buffer_id, + buffer_point, + ); + assert_eq!( + right_point, + excerpt_start.lines + (buffer_right_point - buffer_start_point), + "clip_point({:?}, Right). buffer: {:?}, buffer point: {:?}", + point, + buffer_id, + buffer_point, + ); + + assert_eq!( + snapshot.point_to_offset(left_point), + left_offset, + "point_to_offset({:?})", + left_point, + ); + assert_eq!( + snapshot.offset_to_point(left_offset), + left_point, + "offset_to_point({:?})", + left_offset, + ); + + offset += 1; + buffer_offset += 1; + if ch == '\n' { + point += Point::new(1, 0); + buffer_point += Point::new(1, 0); + } else { + point += Point::new(0, 1); + buffer_point += Point::new(0, 1); + } + } + + for _ in 0..ch.len_utf16() { + let left_point_utf16 = + snapshot.clip_point_utf16(Unclipped(point_utf16), Bias::Left); + let right_point_utf16 = + snapshot.clip_point_utf16(Unclipped(point_utf16), Bias::Right); + let buffer_left_point_utf16 = + buffer.clip_point_utf16(Unclipped(buffer_point_utf16), Bias::Left); + let buffer_right_point_utf16 = + buffer.clip_point_utf16(Unclipped(buffer_point_utf16), Bias::Right); + assert_eq!( + left_point_utf16, + excerpt_start.lines_utf16() + + (buffer_left_point_utf16 - buffer_start_point_utf16), + "clip_point_utf16({:?}, Left). buffer: {:?}, buffer point_utf16: {:?}", + point_utf16, + buffer_id, + buffer_point_utf16, + ); + assert_eq!( + right_point_utf16, + excerpt_start.lines_utf16() + + (buffer_right_point_utf16 - buffer_start_point_utf16), + "clip_point_utf16({:?}, Right). buffer: {:?}, buffer point_utf16: {:?}", + point_utf16, + buffer_id, + buffer_point_utf16, + ); + + if ch == '\n' { + point_utf16 += PointUtf16::new(1, 0); + buffer_point_utf16 += PointUtf16::new(1, 0); + } else { + point_utf16 += PointUtf16::new(0, 1); + buffer_point_utf16 += PointUtf16::new(0, 1); + } + } + } + } + + for (row, line) in expected_text.split('\n').enumerate() { + assert_eq!( + snapshot.line_len(row as u32), + line.len() as u32, + "line_len({}).", + row + ); + } + + let text_rope = Rope::from(expected_text.as_str()); + for _ in 0..10 { + let end_ix = text_rope.clip_offset(rng.gen_range(0..=text_rope.len()), Bias::Right); + let start_ix = text_rope.clip_offset(rng.gen_range(0..=end_ix), Bias::Left); + + let text_for_range = snapshot + .text_for_range(start_ix..end_ix) + .collect::(); + assert_eq!( + text_for_range, + &expected_text[start_ix..end_ix], + "incorrect text for range {:?}", + start_ix..end_ix + ); + + let excerpted_buffer_ranges = multibuffer + .read(cx) + .range_to_buffer_ranges(start_ix..end_ix, cx); + let excerpted_buffers_text = excerpted_buffer_ranges + .iter() + .map(|(buffer, buffer_range, _)| { + buffer + .read(cx) + .text_for_range(buffer_range.clone()) + .collect::() + }) + .collect::>() + .join("\n"); + assert_eq!(excerpted_buffers_text, text_for_range); + if !expected_excerpts.is_empty() { + assert!(!excerpted_buffer_ranges.is_empty()); + } + + let expected_summary = TextSummary::from(&expected_text[start_ix..end_ix]); + assert_eq!( + snapshot.text_summary_for_range::(start_ix..end_ix), + expected_summary, + "incorrect summary for range {:?}", + start_ix..end_ix + ); + } + + // Anchor resolution + let summaries = snapshot.summaries_for_anchors::(&anchors); + assert_eq!(anchors.len(), summaries.len()); + for (anchor, resolved_offset) in anchors.iter().zip(summaries) { + assert!(resolved_offset <= snapshot.len()); + assert_eq!( + snapshot.summary_for_anchor::(anchor), + resolved_offset + ); + } + + for _ in 0..10 { + let end_ix = text_rope.clip_offset(rng.gen_range(0..=text_rope.len()), Bias::Right); + assert_eq!( + snapshot.reversed_chars_at(end_ix).collect::(), + expected_text[..end_ix].chars().rev().collect::(), + ); + } + + for _ in 0..10 { + let end_ix = rng.gen_range(0..=text_rope.len()); + let start_ix = rng.gen_range(0..=end_ix); + assert_eq!( + snapshot + .bytes_in_range(start_ix..end_ix) + .flatten() + .copied() + .collect::>(), + expected_text.as_bytes()[start_ix..end_ix].to_vec(), + "bytes_in_range({:?})", + start_ix..end_ix, + ); + } + } + + let snapshot = multibuffer.read(cx).snapshot(cx); + for (old_snapshot, subscription) in old_versions { + let edits = subscription.consume().into_inner(); + + log::info!( + "applying subscription edits to old text: {:?}: {:?}", + old_snapshot.text(), + edits, + ); + + let mut text = old_snapshot.text(); + for edit in edits { + let new_text: String = snapshot.text_for_range(edit.new.clone()).collect(); + text.replace_range(edit.new.start..edit.new.start + edit.old.len(), &new_text); + } + assert_eq!(text.to_string(), snapshot.text()); + } + } + + #[gpui2::test] + fn test_history(cx: &mut AppContext) { + let test_settings = SettingsStore::test(cx); + cx.set_global(test_settings); + + let buffer_1 = cx.build_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), "1234")); + let buffer_2 = cx.build_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), "5678")); + let multibuffer = cx.build_model(|_| MultiBuffer::new(0)); + let group_interval = multibuffer.read(cx).history.group_interval; + multibuffer.update(cx, |multibuffer, cx| { + multibuffer.push_excerpts( + buffer_1.clone(), + [ExcerptRange { + context: 0..buffer_1.read(cx).len(), + primary: None, + }], + cx, + ); + multibuffer.push_excerpts( + buffer_2.clone(), + [ExcerptRange { + context: 0..buffer_2.read(cx).len(), + primary: None, + }], + cx, + ); + }); + + let mut now = Instant::now(); + + multibuffer.update(cx, |multibuffer, cx| { + let transaction_1 = multibuffer.start_transaction_at(now, cx).unwrap(); + multibuffer.edit( + [ + (Point::new(0, 0)..Point::new(0, 0), "A"), + (Point::new(1, 0)..Point::new(1, 0), "A"), + ], + None, + cx, + ); + multibuffer.edit( + [ + (Point::new(0, 1)..Point::new(0, 1), "B"), + (Point::new(1, 1)..Point::new(1, 1), "B"), + ], + None, + cx, + ); + multibuffer.end_transaction_at(now, cx); + assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678"); + + // Edit buffer 1 through the multibuffer + now += 2 * group_interval; + multibuffer.start_transaction_at(now, cx); + multibuffer.edit([(2..2, "C")], None, cx); + multibuffer.end_transaction_at(now, cx); + assert_eq!(multibuffer.read(cx).text(), "ABC1234\nAB5678"); + + // Edit buffer 1 independently + buffer_1.update(cx, |buffer_1, cx| { + buffer_1.start_transaction_at(now); + buffer_1.edit([(3..3, "D")], None, cx); + buffer_1.end_transaction_at(now, cx); + + now += 2 * group_interval; + buffer_1.start_transaction_at(now); + buffer_1.edit([(4..4, "E")], None, cx); + buffer_1.end_transaction_at(now, cx); + }); + assert_eq!(multibuffer.read(cx).text(), "ABCDE1234\nAB5678"); + + // An undo in the multibuffer undoes the multibuffer transaction + // and also any individual buffer edits that have occurred since + // that transaction. + multibuffer.undo(cx); + assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678"); + + multibuffer.undo(cx); + assert_eq!(multibuffer.read(cx).text(), "1234\n5678"); + + multibuffer.redo(cx); + assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678"); + + multibuffer.redo(cx); + assert_eq!(multibuffer.read(cx).text(), "ABCDE1234\nAB5678"); + + // Undo buffer 2 independently. + buffer_2.update(cx, |buffer_2, cx| buffer_2.undo(cx)); + assert_eq!(multibuffer.read(cx).text(), "ABCDE1234\n5678"); + + // An undo in the multibuffer undoes the components of the + // the last multibuffer transaction that are not already undone. + multibuffer.undo(cx); + assert_eq!(multibuffer.read(cx).text(), "AB1234\n5678"); + + multibuffer.undo(cx); + assert_eq!(multibuffer.read(cx).text(), "1234\n5678"); + + multibuffer.redo(cx); + assert_eq!(multibuffer.read(cx).text(), "AB1234\nAB5678"); + + buffer_1.update(cx, |buffer_1, cx| buffer_1.redo(cx)); + assert_eq!(multibuffer.read(cx).text(), "ABCD1234\nAB5678"); + + // Redo stack gets cleared after an edit. + now += 2 * group_interval; + multibuffer.start_transaction_at(now, cx); + multibuffer.edit([(0..0, "X")], None, cx); + multibuffer.end_transaction_at(now, cx); + assert_eq!(multibuffer.read(cx).text(), "XABCD1234\nAB5678"); + multibuffer.redo(cx); + assert_eq!(multibuffer.read(cx).text(), "XABCD1234\nAB5678"); + multibuffer.undo(cx); + assert_eq!(multibuffer.read(cx).text(), "ABCD1234\nAB5678"); + multibuffer.undo(cx); + assert_eq!(multibuffer.read(cx).text(), "1234\n5678"); + + // Transactions can be grouped manually. + multibuffer.redo(cx); + multibuffer.redo(cx); + assert_eq!(multibuffer.read(cx).text(), "XABCD1234\nAB5678"); + multibuffer.group_until_transaction(transaction_1, cx); + multibuffer.undo(cx); + assert_eq!(multibuffer.read(cx).text(), "1234\n5678"); + multibuffer.redo(cx); + assert_eq!(multibuffer.read(cx).text(), "XABCD1234\nAB5678"); + }); + } +} diff --git a/crates/prettier/src/prettier_server.js b/crates/prettier/src/prettier_server.js index a56c220f20..9967aec50f 100644 --- a/crates/prettier/src/prettier_server.js +++ b/crates/prettier/src/prettier_server.js @@ -55,8 +55,11 @@ async function handleBuffer(prettier) { } // allow concurrent request handling by not `await`ing the message handling promise (async function) handleMessage(message, prettier).catch(e => { - sendResponse({ id: message.id, ...makeError(`error during message handling: ${e}`) }); - }); + const errorMessage = message; + if ((errorMessage.params || {}).text !== undefined) { + errorMessage.params.text = "..snip.."; + } + sendResponse({ id: message.id, ...makeError(`error during message '${JSON.stringify(errorMessage)}' handling: ${e}`) }); }); } } @@ -172,7 +175,7 @@ async function handleMessage(message, prettier) { sendResponse({ id, result: null }); } else if (method === 'initialize') { sendResponse({ - id, + id: id || 0, result: { "capabilities": {} } diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index 3e5bcef00c..b38bcd1db2 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -162,12 +162,20 @@ pub struct Project { copilot_log_subscription: Option, current_lsp_settings: HashMap, LspSettings>, node: Option>, + #[cfg(not(any(test, feature = "test-support")))] + default_prettier: Option, prettier_instances: HashMap< (Option, PathBuf), Shared, Arc>>>, >, } +#[cfg(not(any(test, feature = "test-support")))] +struct DefaultPrettier { + installation_process: Option>>, + installed_plugins: HashSet<&'static str>, +} + struct DelayedDebounced { task: Option>, cancel_channel: Option>, @@ -677,6 +685,8 @@ impl Project { copilot_log_subscription: None, current_lsp_settings: settings::get::(cx).lsp.clone(), node: Some(node), + #[cfg(not(any(test, feature = "test-support")))] + default_prettier: None, prettier_instances: HashMap::default(), } }) @@ -776,6 +786,8 @@ impl Project { copilot_log_subscription: None, current_lsp_settings: settings::get::(cx).lsp.clone(), node: None, + #[cfg(not(any(test, feature = "test-support")))] + default_prettier: None, prettier_instances: HashMap::default(), }; for worktree in worktrees { @@ -8497,7 +8509,7 @@ impl Project { #[cfg(any(test, feature = "test-support"))] fn install_default_formatters( - &self, + &mut self, _worktree: Option, _new_language: &Language, _language_settings: &LanguageSettings, @@ -8508,7 +8520,7 @@ impl Project { #[cfg(not(any(test, feature = "test-support")))] fn install_default_formatters( - &self, + &mut self, worktree: Option, new_language: &Language, language_settings: &LanguageSettings, @@ -8537,51 +8549,108 @@ impl Project { return Task::ready(Ok(())); }; + let mut plugins_to_install = prettier_plugins; + let (mut install_success_tx, mut install_success_rx) = + futures::channel::mpsc::channel::>(1); + let new_installation_process = cx + .spawn(|this, mut cx| async move { + if let Some(installed_plugins) = install_success_rx.next().await { + this.update(&mut cx, |this, _| { + let default_prettier = + this.default_prettier + .get_or_insert_with(|| DefaultPrettier { + installation_process: None, + installed_plugins: HashSet::default(), + }); + if !installed_plugins.is_empty() { + log::info!("Installed new prettier plugins: {installed_plugins:?}"); + default_prettier.installed_plugins.extend(installed_plugins); + } + }) + } + }) + .shared(); + let previous_installation_process = + if let Some(default_prettier) = &mut self.default_prettier { + plugins_to_install + .retain(|plugin| !default_prettier.installed_plugins.contains(plugin)); + if plugins_to_install.is_empty() { + return Task::ready(Ok(())); + } + std::mem::replace( + &mut default_prettier.installation_process, + Some(new_installation_process.clone()), + ) + } else { + None + }; + let default_prettier_dir = util::paths::DEFAULT_PRETTIER_DIR.as_path(); let already_running_prettier = self .prettier_instances .get(&(worktree, default_prettier_dir.to_path_buf())) .cloned(); - let fs = Arc::clone(&self.fs); - cx.background() - .spawn(async move { - let prettier_wrapper_path = default_prettier_dir.join(prettier::PRETTIER_SERVER_FILE); - // method creates parent directory if it doesn't exist - fs.save(&prettier_wrapper_path, &text::Rope::from(prettier::PRETTIER_SERVER_JS), text::LineEnding::Unix).await - .with_context(|| format!("writing {} file at {prettier_wrapper_path:?}", prettier::PRETTIER_SERVER_FILE))?; - - let packages_to_versions = future::try_join_all( - prettier_plugins - .iter() - .chain(Some(&"prettier")) - .map(|package_name| async { - let returned_package_name = package_name.to_string(); - let latest_version = node.npm_package_latest_version(package_name) - .await - .with_context(|| { - format!("fetching latest npm version for package {returned_package_name}") - })?; - anyhow::Ok((returned_package_name, latest_version)) - }), - ) - .await - .context("fetching latest npm versions")?; - - log::info!("Fetching default prettier and plugins: {packages_to_versions:?}"); - let borrowed_packages = packages_to_versions.iter().map(|(package, version)| { - (package.as_str(), version.as_str()) - }).collect::>(); - node.npm_install_packages(default_prettier_dir, &borrowed_packages).await.context("fetching formatter packages")?; - - if !prettier_plugins.is_empty() { - if let Some(prettier) = already_running_prettier { - prettier.await.map_err(|e| anyhow::anyhow!("Default prettier startup await failure: {e:#}"))?.clear_cache().await.context("clearing default prettier cache after plugins install")?; - } + cx.spawn(|this, mut cx| async move { + if let Some(previous_installation_process) = previous_installation_process { + previous_installation_process.await; + } + let mut everything_was_installed = false; + this.update(&mut cx, |this, _| { + match &mut this.default_prettier { + Some(default_prettier) => { + plugins_to_install + .retain(|plugin| !default_prettier.installed_plugins.contains(plugin)); + everything_was_installed = plugins_to_install.is_empty(); + }, + None => this.default_prettier = Some(DefaultPrettier { installation_process: Some(new_installation_process), installed_plugins: HashSet::default() }), } + }); + if everything_was_installed { + return Ok(()); + } - anyhow::Ok(()) - }) + cx.background() + .spawn(async move { + let prettier_wrapper_path = default_prettier_dir.join(prettier::PRETTIER_SERVER_FILE); + // method creates parent directory if it doesn't exist + fs.save(&prettier_wrapper_path, &text::Rope::from(prettier::PRETTIER_SERVER_JS), text::LineEnding::Unix).await + .with_context(|| format!("writing {} file at {prettier_wrapper_path:?}", prettier::PRETTIER_SERVER_FILE))?; + + let packages_to_versions = future::try_join_all( + plugins_to_install + .iter() + .chain(Some(&"prettier")) + .map(|package_name| async { + let returned_package_name = package_name.to_string(); + let latest_version = node.npm_package_latest_version(package_name) + .await + .with_context(|| { + format!("fetching latest npm version for package {returned_package_name}") + })?; + anyhow::Ok((returned_package_name, latest_version)) + }), + ) + .await + .context("fetching latest npm versions")?; + + log::info!("Fetching default prettier and plugins: {packages_to_versions:?}"); + let borrowed_packages = packages_to_versions.iter().map(|(package, version)| { + (package.as_str(), version.as_str()) + }).collect::>(); + node.npm_install_packages(default_prettier_dir, &borrowed_packages).await.context("fetching formatter packages")?; + let installed_packages = !plugins_to_install.is_empty(); + install_success_tx.try_send(plugins_to_install).ok(); + + if !installed_packages { + if let Some(prettier) = already_running_prettier { + prettier.await.map_err(|e| anyhow::anyhow!("Default prettier startup await failure: {e:#}"))?.clear_cache().await.context("clearing default prettier cache after plugins install")?; + } + } + + anyhow::Ok(()) + }).await + }) } } diff --git a/crates/project/src/worktree.rs b/crates/project/src/worktree.rs index f6fae0c98b..80fd44761c 100644 --- a/crates/project/src/worktree.rs +++ b/crates/project/src/worktree.rs @@ -2662,12 +2662,12 @@ impl language::File for File { impl language::LocalFile for File { fn abs_path(&self, cx: &AppContext) -> PathBuf { - self.worktree - .read(cx) - .as_local() - .unwrap() - .abs_path - .join(&self.path) + let worktree_path = &self.worktree.read(cx).as_local().unwrap().abs_path; + if self.path.as_ref() == Path::new("") { + worktree_path.to_path_buf() + } else { + worktree_path.join(&self.path) + } } fn load(&self, cx: &AppContext) -> Task> { diff --git a/crates/storybook2/src/stories/colors.rs b/crates/storybook2/src/stories/colors.rs index afc29660ff..0dd56071c8 100644 --- a/crates/storybook2/src/stories/colors.rs +++ b/crates/storybook2/src/stories/colors.rs @@ -1,5 +1,6 @@ use crate::story::Story; use gpui2::{px, Div, Render}; +use theme2::default_color_scales; use ui::prelude::*; pub struct ColorsStory; @@ -8,7 +9,7 @@ impl Render for ColorsStory { type Element = Div; fn render(&mut self, cx: &mut ViewContext) -> Self::Element { - let color_scales = theme2::default_color_scales(); + let color_scales = default_color_scales(); Story::container(cx) .child(Story::title(cx, "Colors")) @@ -20,14 +21,14 @@ impl Render for ColorsStory { .gap_1() .overflow_y_scroll() .text_color(gpui2::white()) - .children(color_scales.into_iter().map(|(name, scale)| { + .children(color_scales.into_iter().map(|scale| { div() .flex() .child( div() .w(px(75.)) .line_height(px(24.)) - .child(name.to_string()), + .child(scale.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 f3f6a8d5fb..aa71040b47 100644 --- a/crates/storybook2/src/stories/focus.rs +++ b/crates/storybook2/src/stories/focus.rs @@ -3,7 +3,7 @@ use gpui2::{ StatelessInteractive, Styled, View, VisualContext, WindowContext, }; use serde::Deserialize; -use theme2::theme; +use theme2::ActiveTheme; #[derive(Clone, Default, PartialEq, Deserialize)] struct ActionA; @@ -34,13 +34,13 @@ 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 theme = cx.theme(); + let color_1 = theme.styles.git.created; + let color_2 = theme.styles.git.modified; + let color_3 = theme.styles.git.deleted; + let color_4 = theme.styles.git.conflict; + let color_5 = theme.styles.git.ignored; + let color_6 = theme.styles.git.renamed; let child_1 = cx.focus_handle(); let child_2 = cx.focus_handle(); diff --git a/crates/storybook2/src/stories/scroll.rs b/crates/storybook2/src/stories/scroll.rs index b504a512a6..9236629c34 100644 --- a/crates/storybook2/src/stories/scroll.rs +++ b/crates/storybook2/src/stories/scroll.rs @@ -2,7 +2,7 @@ use gpui2::{ div, px, Component, Div, ParentElement, Render, SharedString, StatefulInteraction, Styled, View, VisualContext, WindowContext, }; -use theme2::theme; +use theme2::ActiveTheme; pub struct ScrollStory; @@ -16,13 +16,13 @@ impl Render for ScrollStory { type Element = Div>; 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 theme = cx.theme(); + let color_1 = theme.styles.git.created; + let color_2 = theme.styles.git.modified; div() .id("parent") - .bg(theme.background) + .bg(theme.colors().background) .size_full() .overflow_scroll() .children((0..10).map(|row| { diff --git a/crates/storybook2/src/storybook2.rs b/crates/storybook2/src/storybook2.rs index c2903c88e1..3b5722732b 100644 --- a/crates/storybook2/src/storybook2.rs +++ b/crates/storybook2/src/storybook2.rs @@ -48,7 +48,7 @@ fn main() { let args = Args::parse(); let story_selector = args.story.clone(); - let theme_name = args.theme.unwrap_or("One Dark".to_string()); + let theme_name = args.theme.unwrap_or("Zed Pro Moonlight".to_string()); let asset_source = Arc::new(Assets); gpui2::App::production(asset_source).run(move |cx| { @@ -71,7 +71,6 @@ fn main() { theme_settings.active_theme = theme_registry.get(&theme_name).unwrap(); ThemeSettings::override_global(theme_settings, cx); - cx.set_global(theme.clone()); ui::settings::init(cx); let window = cx.open_window( @@ -82,7 +81,12 @@ fn main() { }), ..Default::default() }, - move |cx| cx.build_view(|cx| StoryWrapper::new(selector.story(cx))), + move |cx| { + let theme_settings = ThemeSettings::get_global(cx); + cx.set_rem_size(theme_settings.ui_font_size); + + cx.build_view(|cx| StoryWrapper::new(selector.story(cx))) + }, ); cx.activate(true); diff --git a/crates/theme2/Cargo.toml b/crates/theme2/Cargo.toml index 2f89425d21..6b273e5042 100644 --- a/crates/theme2/Cargo.toml +++ b/crates/theme2/Cargo.toml @@ -16,19 +16,19 @@ path = "src/theme2.rs" doctest = false [dependencies] -gpui2 = { path = "../gpui2" } -fs = { path = "../fs" } -schemars.workspace = true -settings2 = { path = "../settings2" } -util = { path = "../util" } - anyhow.workspace = true +fs = { path = "../fs" } +gpui2 = { path = "../gpui2" } indexmap = "1.6.2" parking_lot.workspace = true +refineable.workspace = true +schemars.workspace = true serde.workspace = true serde_derive.workspace = true serde_json.workspace = true +settings2 = { path = "../settings2" } toml.workspace = true +util = { path = "../util" } [dev-dependencies] gpui2 = { path = "../gpui2", features = ["test-support"] } diff --git a/crates/theme2/src/colors.rs b/crates/theme2/src/colors.rs new file mode 100644 index 0000000000..02c93a2e98 --- /dev/null +++ b/crates/theme2/src/colors.rs @@ -0,0 +1,144 @@ +use gpui2::Hsla; +use refineable::Refineable; + +use crate::SyntaxTheme; + +#[derive(Clone)] +pub struct SystemColors { + pub transparent: Hsla, + pub mac_os_traffic_light_red: Hsla, + pub mac_os_traffic_light_yellow: Hsla, + pub mac_os_traffic_light_green: Hsla, +} + +#[derive(Debug, Clone, Copy)] +pub struct PlayerColor { + pub cursor: Hsla, + pub background: Hsla, + pub selection: Hsla, +} + +#[derive(Clone)] +pub struct PlayerColors(pub Vec); + +#[derive(Refineable, Clone, Debug)] +#[refineable(debug)] +pub struct StatusColors { + pub conflict: Hsla, + pub created: Hsla, + pub deleted: Hsla, + pub error: Hsla, + pub hidden: Hsla, + pub ignored: Hsla, + pub info: Hsla, + pub modified: Hsla, + pub renamed: Hsla, + pub success: Hsla, + pub warning: Hsla, +} + +#[derive(Refineable, Clone, Debug)] +#[refineable(debug)] +pub struct GitStatusColors { + pub conflict: Hsla, + pub created: Hsla, + pub deleted: Hsla, + pub ignored: Hsla, + pub modified: Hsla, + pub renamed: Hsla, +} + +#[derive(Refineable, Clone, Debug, Default)] +#[refineable(debug)] +pub struct ThemeColors { + pub border: Hsla, + pub border_variant: Hsla, + pub border_focused: Hsla, + pub border_transparent: Hsla, + pub elevated_surface: Hsla, + pub surface: Hsla, + pub background: Hsla, + pub element: Hsla, + pub element_hover: Hsla, + pub element_active: Hsla, + pub element_selected: Hsla, + pub element_disabled: Hsla, + pub element_placeholder: Hsla, + pub ghost_element: Hsla, + pub ghost_element_hover: Hsla, + pub ghost_element_active: Hsla, + pub ghost_element_selected: Hsla, + pub ghost_element_disabled: Hsla, + pub text: Hsla, + pub text_muted: Hsla, + pub text_placeholder: Hsla, + pub text_disabled: Hsla, + pub text_accent: Hsla, + pub icon: Hsla, + pub icon_muted: Hsla, + pub icon_disabled: Hsla, + pub icon_placeholder: Hsla, + pub icon_accent: Hsla, + pub status_bar: Hsla, + pub title_bar: Hsla, + pub toolbar: Hsla, + pub tab_bar: Hsla, + pub editor: Hsla, + pub editor_subheader: Hsla, + pub editor_active_line: Hsla, +} + +#[derive(Refineable, Clone)] +pub struct ThemeStyles { + pub system: SystemColors, + pub colors: ThemeColors, + pub status: StatusColors, + pub git: GitStatusColors, + pub player: PlayerColors, + pub syntax: SyntaxTheme, +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn override_a_single_theme_color() { + let mut colors = ThemeColors::default_light(); + + let magenta: Hsla = gpui2::rgb(0xff00ff); + + assert_ne!(colors.text, magenta); + + let overrides = ThemeColorsRefinement { + text: Some(magenta), + ..Default::default() + }; + + colors.refine(&overrides); + + assert_eq!(colors.text, magenta); + } + + #[test] + fn override_multiple_theme_colors() { + let mut colors = ThemeColors::default_light(); + + let magenta: Hsla = gpui2::rgb(0xff00ff); + let green: Hsla = gpui2::rgb(0x00ff00); + + assert_ne!(colors.text, magenta); + assert_ne!(colors.background, green); + + let overrides = ThemeColorsRefinement { + text: Some(magenta), + background: Some(green), + ..Default::default() + }; + + colors.refine(&overrides); + + assert_eq!(colors.text, magenta); + assert_eq!(colors.background, green); + } +} diff --git a/crates/theme2/src/default.rs b/crates/theme2/src/default_colors.rs similarity index 75% rename from crates/theme2/src/default.rs rename to crates/theme2/src/default_colors.rs index 41d408f980..8fb38e9661 100644 --- a/crates/theme2/src/default.rs +++ b/crates/theme2/src/default_colors.rs @@ -1,10 +1,276 @@ -use gpui2::Rgba; -use indexmap::IndexMap; +use gpui2::{hsla, Rgba}; -use crate::scale::{ColorScaleName, ColorScaleSet, ColorScales}; +use crate::{ + colors::{GitStatusColors, PlayerColor, PlayerColors, StatusColors, SystemColors, ThemeColors}, + scale::{ColorScaleSet, ColorScales}, + syntax::SyntaxTheme, +}; + +impl Default for SystemColors { + fn default() -> Self { + Self { + transparent: hsla(0.0, 0.0, 0.0, 0.0), + mac_os_traffic_light_red: hsla(0.0139, 0.79, 0.65, 1.0), + mac_os_traffic_light_yellow: hsla(0.114, 0.88, 0.63, 1.0), + mac_os_traffic_light_green: hsla(0.313, 0.49, 0.55, 1.0), + } + } +} + +impl Default for StatusColors { + fn default() -> Self { + Self { + conflict: gpui2::black(), + created: gpui2::black(), + deleted: gpui2::black(), + error: gpui2::black(), + hidden: gpui2::black(), + ignored: gpui2::black(), + info: gpui2::black(), + modified: gpui2::black(), + renamed: gpui2::black(), + success: gpui2::black(), + warning: gpui2::black(), + } + } +} + +impl Default for GitStatusColors { + fn default() -> Self { + Self { + conflict: gpui2::rgba(0xdec184ff).into(), + created: gpui2::rgba(0xa1c181ff).into(), + deleted: gpui2::rgba(0xd07277ff).into(), + ignored: gpui2::rgba(0x555a63ff).into(), + modified: gpui2::rgba(0x74ade8ff).into(), + renamed: gpui2::rgba(0xdec184ff).into(), + } + } +} + +impl Default for PlayerColors { + fn default() -> Self { + Self(vec![ + PlayerColor { + cursor: hsla(0.0, 0.0, 0.0, 0.0), + background: hsla(0.0, 0.0, 0.0, 0.0), + selection: hsla(0.0, 0.0, 0.0, 0.0), + }, + PlayerColor { + cursor: hsla(0.0, 0.0, 0.0, 0.0), + background: hsla(0.0, 0.0, 0.0, 0.0), + selection: hsla(0.0, 0.0, 0.0, 0.0), + }, + PlayerColor { + cursor: hsla(0.0, 0.0, 0.0, 0.0), + background: hsla(0.0, 0.0, 0.0, 0.0), + selection: hsla(0.0, 0.0, 0.0, 0.0), + }, + PlayerColor { + cursor: hsla(0.0, 0.0, 0.0, 0.0), + background: hsla(0.0, 0.0, 0.0, 0.0), + selection: hsla(0.0, 0.0, 0.0, 0.0), + }, + ]) + } +} + +impl SyntaxTheme { + pub fn default_light() -> Self { + Self { + highlights: vec![ + ( + "string.special.symbol".into(), + gpui2::rgba(0xad6e26ff).into(), + ), + ("hint".into(), gpui2::rgba(0x9294beff).into()), + ("link_uri".into(), gpui2::rgba(0x3882b7ff).into()), + ("type".into(), gpui2::rgba(0x3882b7ff).into()), + ("string.regex".into(), gpui2::rgba(0xad6e26ff).into()), + ("constant".into(), gpui2::rgba(0x669f59ff).into()), + ("function".into(), gpui2::rgba(0x5b79e3ff).into()), + ("string.special".into(), gpui2::rgba(0xad6e26ff).into()), + ("punctuation.bracket".into(), gpui2::rgba(0x4d4f52ff).into()), + ("variable".into(), gpui2::rgba(0x383a41ff).into()), + ("punctuation".into(), gpui2::rgba(0x383a41ff).into()), + ("property".into(), gpui2::rgba(0xd3604fff).into()), + ("string".into(), gpui2::rgba(0x649f57ff).into()), + ("predictive".into(), gpui2::rgba(0x9b9ec6ff).into()), + ("attribute".into(), gpui2::rgba(0x5c78e2ff).into()), + ("number".into(), gpui2::rgba(0xad6e25ff).into()), + ("constructor".into(), gpui2::rgba(0x5c78e2ff).into()), + ("embedded".into(), gpui2::rgba(0x383a41ff).into()), + ("title".into(), gpui2::rgba(0xd3604fff).into()), + ("tag".into(), gpui2::rgba(0x5c78e2ff).into()), + ("boolean".into(), gpui2::rgba(0xad6e25ff).into()), + ( + "punctuation.list_marker".into(), + gpui2::rgba(0xd3604fff).into(), + ), + ("variant".into(), gpui2::rgba(0x5b79e3ff).into()), + ("emphasis".into(), gpui2::rgba(0x5c78e2ff).into()), + ("link_text".into(), gpui2::rgba(0x5b79e3ff).into()), + ("comment".into(), gpui2::rgba(0xa2a3a7ff).into()), + ("punctuation.special".into(), gpui2::rgba(0xb92b46ff).into()), + ("emphasis.strong".into(), gpui2::rgba(0xad6e25ff).into()), + ("primary".into(), gpui2::rgba(0x383a41ff).into()), + ( + "punctuation.delimiter".into(), + gpui2::rgba(0x4d4f52ff).into(), + ), + ("label".into(), gpui2::rgba(0x5c78e2ff).into()), + ("keyword".into(), gpui2::rgba(0xa449abff).into()), + ("string.escape".into(), gpui2::rgba(0x7c7e86ff).into()), + ("text.literal".into(), gpui2::rgba(0x649f57ff).into()), + ("variable.special".into(), gpui2::rgba(0xad6e25ff).into()), + ("comment.doc".into(), gpui2::rgba(0x7c7e86ff).into()), + ("enum".into(), gpui2::rgba(0xd3604fff).into()), + ("operator".into(), gpui2::rgba(0x3882b7ff).into()), + ("preproc".into(), gpui2::rgba(0x383a41ff).into()), + ], + } + } + + pub fn default_dark() -> Self { + Self { + highlights: vec![ + ("keyword".into(), gpui2::rgba(0xb477cfff).into()), + ("comment.doc".into(), gpui2::rgba(0x878e98ff).into()), + ("variant".into(), gpui2::rgba(0x73ade9ff).into()), + ("property".into(), gpui2::rgba(0xd07277ff).into()), + ("function".into(), gpui2::rgba(0x73ade9ff).into()), + ("type".into(), gpui2::rgba(0x6eb4bfff).into()), + ("tag".into(), gpui2::rgba(0x74ade8ff).into()), + ("string.escape".into(), gpui2::rgba(0x878e98ff).into()), + ("punctuation.bracket".into(), gpui2::rgba(0xb2b9c6ff).into()), + ("hint".into(), gpui2::rgba(0x5a6f89ff).into()), + ("punctuation".into(), gpui2::rgba(0xacb2beff).into()), + ("comment".into(), gpui2::rgba(0x5d636fff).into()), + ("emphasis".into(), gpui2::rgba(0x74ade8ff).into()), + ("punctuation.special".into(), gpui2::rgba(0xb1574bff).into()), + ("link_uri".into(), gpui2::rgba(0x6eb4bfff).into()), + ("string.regex".into(), gpui2::rgba(0xbf956aff).into()), + ("constructor".into(), gpui2::rgba(0x73ade9ff).into()), + ("operator".into(), gpui2::rgba(0x6eb4bfff).into()), + ("constant".into(), gpui2::rgba(0xdfc184ff).into()), + ("string.special".into(), gpui2::rgba(0xbf956aff).into()), + ("emphasis.strong".into(), gpui2::rgba(0xbf956aff).into()), + ( + "string.special.symbol".into(), + gpui2::rgba(0xbf956aff).into(), + ), + ("primary".into(), gpui2::rgba(0xacb2beff).into()), + ("preproc".into(), gpui2::rgba(0xc8ccd4ff).into()), + ("string".into(), gpui2::rgba(0xa1c181ff).into()), + ( + "punctuation.delimiter".into(), + gpui2::rgba(0xb2b9c6ff).into(), + ), + ("embedded".into(), gpui2::rgba(0xc8ccd4ff).into()), + ("enum".into(), gpui2::rgba(0xd07277ff).into()), + ("variable.special".into(), gpui2::rgba(0xbf956aff).into()), + ("text.literal".into(), gpui2::rgba(0xa1c181ff).into()), + ("attribute".into(), gpui2::rgba(0x74ade8ff).into()), + ("link_text".into(), gpui2::rgba(0x73ade9ff).into()), + ("title".into(), gpui2::rgba(0xd07277ff).into()), + ("predictive".into(), gpui2::rgba(0x5a6a87ff).into()), + ("number".into(), gpui2::rgba(0xbf956aff).into()), + ("label".into(), gpui2::rgba(0x74ade8ff).into()), + ("variable".into(), gpui2::rgba(0xc8ccd4ff).into()), + ("boolean".into(), gpui2::rgba(0xbf956aff).into()), + ( + "punctuation.list_marker".into(), + gpui2::rgba(0xd07277ff).into(), + ), + ], + } + } +} + +impl ThemeColors { + pub fn default_light() -> Self { + Self { + border: gpui2::white(), + border_variant: gpui2::white(), + border_focused: gpui2::white(), + border_transparent: gpui2::white(), + elevated_surface: gpui2::white(), + surface: gpui2::white(), + background: gpui2::white(), + element: gpui2::white(), + element_hover: gpui2::white(), + element_active: gpui2::white(), + element_selected: gpui2::white(), + element_disabled: gpui2::white(), + element_placeholder: gpui2::white(), + ghost_element: gpui2::white(), + ghost_element_hover: gpui2::white(), + ghost_element_active: gpui2::white(), + ghost_element_selected: gpui2::white(), + ghost_element_disabled: gpui2::white(), + text: gpui2::white(), + text_muted: gpui2::white(), + text_placeholder: gpui2::white(), + text_disabled: gpui2::white(), + text_accent: gpui2::white(), + icon: gpui2::white(), + icon_muted: gpui2::white(), + icon_disabled: gpui2::white(), + icon_placeholder: gpui2::white(), + icon_accent: gpui2::white(), + status_bar: gpui2::white(), + title_bar: gpui2::white(), + toolbar: gpui2::white(), + tab_bar: gpui2::white(), + editor: gpui2::white(), + editor_subheader: gpui2::white(), + editor_active_line: gpui2::white(), + } + } + + pub fn default_dark() -> Self { + Self { + border: gpui2::rgba(0x464b57ff).into(), + border_variant: gpui2::rgba(0x464b57ff).into(), + border_focused: gpui2::rgba(0x293b5bff).into(), + border_transparent: gpui2::rgba(0x00000000).into(), + elevated_surface: gpui2::rgba(0x3b414dff).into(), + surface: gpui2::rgba(0x2f343eff).into(), + background: gpui2::rgba(0x3b414dff).into(), + element: gpui2::rgba(0x3b414dff).into(), + element_hover: gpui2::rgba(0xffffff1e).into(), + element_active: gpui2::rgba(0xffffff28).into(), + element_selected: gpui2::rgba(0x18243dff).into(), + element_disabled: gpui2::rgba(0x00000000).into(), + element_placeholder: gpui2::black(), + ghost_element: gpui2::rgba(0x00000000).into(), + ghost_element_hover: gpui2::rgba(0xffffff14).into(), + ghost_element_active: gpui2::rgba(0xffffff1e).into(), + ghost_element_selected: gpui2::rgba(0x18243dff).into(), + ghost_element_disabled: gpui2::rgba(0x00000000).into(), + text: gpui2::rgba(0xc8ccd4ff).into(), + text_muted: gpui2::rgba(0x838994ff).into(), + text_placeholder: gpui2::rgba(0xd07277ff).into(), + text_disabled: gpui2::rgba(0x555a63ff).into(), + text_accent: gpui2::rgba(0x74ade8ff).into(), + icon: gpui2::black(), + icon_muted: gpui2::rgba(0x838994ff).into(), + icon_disabled: gpui2::black(), + icon_placeholder: gpui2::black(), + icon_accent: gpui2::black(), + status_bar: gpui2::rgba(0x3b414dff).into(), + title_bar: gpui2::rgba(0x3b414dff).into(), + toolbar: gpui2::rgba(0x282c33ff).into(), + tab_bar: gpui2::rgba(0x2f343eff).into(), + editor: gpui2::rgba(0x282c33ff).into(), + editor_subheader: gpui2::rgba(0x2f343eff).into(), + editor_active_line: gpui2::rgba(0x2f343eff).into(), + } + } +} struct DefaultColorScaleSet { - scale: ColorScaleName, + scale: &'static str, light: [&'static str; 12], light_alpha: [&'static str; 12], dark: [&'static str; 12], @@ -32,48 +298,46 @@ impl From for ColorScaleSet { } 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()), - ]) + ColorScales { + gray: gray(), + mauve: mauve(), + slate: slate(), + sage: sage(), + olive: olive(), + sand: sand(), + gold: gold(), + bronze: bronze(), + brown: brown(), + yellow: yellow(), + amber: amber(), + orange: orange(), + tomato: tomato(), + red: red(), + ruby: ruby(), + crimson: crimson(), + pink: pink(), + plum: plum(), + purple: purple(), + violet: violet(), + iris: iris(), + indigo: indigo(), + blue: blue(), + cyan: cyan(), + teal: teal(), + jade: jade(), + green: green(), + grass: grass(), + lime: lime(), + mint: mint(), + sky: sky(), + black: black(), + white: white(), + } } -fn gray() -> DefaultColorScaleSet { +fn gray() -> ColorScaleSet { DefaultColorScaleSet { - scale: ColorScaleName::Gray, + scale: "Gray", light: [ "#fcfcfcff", "#f9f9f9ff", @@ -131,11 +395,12 @@ fn gray() -> DefaultColorScaleSet { "#ffffffed", ], } + .into() } -fn mauve() -> DefaultColorScaleSet { +fn mauve() -> ColorScaleSet { DefaultColorScaleSet { - scale: ColorScaleName::Mauve, + scale: "Mauve", light: [ "#fdfcfdff", "#faf9fbff", @@ -193,11 +458,12 @@ fn mauve() -> DefaultColorScaleSet { "#fdfdffef", ], } + .into() } -fn slate() -> DefaultColorScaleSet { +fn slate() -> ColorScaleSet { DefaultColorScaleSet { - scale: ColorScaleName::Slate, + scale: "Slate", light: [ "#fcfcfdff", "#f9f9fbff", @@ -255,11 +521,12 @@ fn slate() -> DefaultColorScaleSet { "#fcfdffef", ], } + .into() } -fn sage() -> DefaultColorScaleSet { +fn sage() -> ColorScaleSet { DefaultColorScaleSet { - scale: ColorScaleName::Sage, + scale: "Sage", light: [ "#fbfdfcff", "#f7f9f8ff", @@ -317,11 +584,12 @@ fn sage() -> DefaultColorScaleSet { "#fdfffeed", ], } + .into() } -fn olive() -> DefaultColorScaleSet { +fn olive() -> ColorScaleSet { DefaultColorScaleSet { - scale: ColorScaleName::Olive, + scale: "Olive", light: [ "#fcfdfcff", "#f8faf8ff", @@ -379,11 +647,12 @@ fn olive() -> DefaultColorScaleSet { "#fdfffded", ], } + .into() } -fn sand() -> DefaultColorScaleSet { +fn sand() -> ColorScaleSet { DefaultColorScaleSet { - scale: ColorScaleName::Sand, + scale: "Sand", light: [ "#fdfdfcff", "#f9f9f8ff", @@ -441,11 +710,12 @@ fn sand() -> DefaultColorScaleSet { "#fffffded", ], } + .into() } -fn gold() -> DefaultColorScaleSet { +fn gold() -> ColorScaleSet { DefaultColorScaleSet { - scale: ColorScaleName::Gold, + scale: "Gold", light: [ "#fdfdfcff", "#faf9f2ff", @@ -503,11 +773,12 @@ fn gold() -> DefaultColorScaleSet { "#fef7ede7", ], } + .into() } -fn bronze() -> DefaultColorScaleSet { +fn bronze() -> ColorScaleSet { DefaultColorScaleSet { - scale: ColorScaleName::Bronze, + scale: "Bronze", light: [ "#fdfcfcff", "#fdf7f5ff", @@ -565,11 +836,12 @@ fn bronze() -> DefaultColorScaleSet { "#fff1e9ec", ], } + .into() } -fn brown() -> DefaultColorScaleSet { +fn brown() -> ColorScaleSet { DefaultColorScaleSet { - scale: ColorScaleName::Brown, + scale: "Brown", light: [ "#fefdfcff", "#fcf9f6ff", @@ -627,11 +899,12 @@ fn brown() -> DefaultColorScaleSet { "#feecd4f2", ], } + .into() } -fn yellow() -> DefaultColorScaleSet { +fn yellow() -> ColorScaleSet { DefaultColorScaleSet { - scale: ColorScaleName::Yellow, + scale: "Yellow", light: [ "#fdfdf9ff", "#fefce9ff", @@ -689,11 +962,12 @@ fn yellow() -> DefaultColorScaleSet { "#fef6baf6", ], } + .into() } -fn amber() -> DefaultColorScaleSet { +fn amber() -> ColorScaleSet { DefaultColorScaleSet { - scale: ColorScaleName::Amber, + scale: "Amber", light: [ "#fefdfbff", "#fefbe9ff", @@ -751,11 +1025,12 @@ fn amber() -> DefaultColorScaleSet { "#ffe7b3ff", ], } + .into() } -fn orange() -> DefaultColorScaleSet { +fn orange() -> ColorScaleSet { DefaultColorScaleSet { - scale: ColorScaleName::Orange, + scale: "Orange", light: [ "#fefcfbff", "#fff7edff", @@ -813,11 +1088,12 @@ fn orange() -> DefaultColorScaleSet { "#ffe0c2ff", ], } + .into() } -fn tomato() -> DefaultColorScaleSet { +fn tomato() -> ColorScaleSet { DefaultColorScaleSet { - scale: ColorScaleName::Tomato, + scale: "Tomato", light: [ "#fffcfcff", "#fff8f7ff", @@ -875,11 +1151,12 @@ fn tomato() -> DefaultColorScaleSet { "#ffd6cefb", ], } + .into() } -fn red() -> DefaultColorScaleSet { +fn red() -> ColorScaleSet { DefaultColorScaleSet { - scale: ColorScaleName::Red, + scale: "Red", light: [ "#fffcfcff", "#fff7f7ff", @@ -937,11 +1214,12 @@ fn red() -> DefaultColorScaleSet { "#ffd1d9ff", ], } + .into() } -fn ruby() -> DefaultColorScaleSet { +fn ruby() -> ColorScaleSet { DefaultColorScaleSet { - scale: ColorScaleName::Ruby, + scale: "Ruby", light: [ "#fffcfdff", "#fff7f8ff", @@ -999,11 +1277,12 @@ fn ruby() -> DefaultColorScaleSet { "#ffd3e2fe", ], } + .into() } -fn crimson() -> DefaultColorScaleSet { +fn crimson() -> ColorScaleSet { DefaultColorScaleSet { - scale: ColorScaleName::Crimson, + scale: "Crimson", light: [ "#fffcfdff", "#fef7f9ff", @@ -1061,11 +1340,12 @@ fn crimson() -> DefaultColorScaleSet { "#ffd5eafd", ], } + .into() } -fn pink() -> DefaultColorScaleSet { +fn pink() -> ColorScaleSet { DefaultColorScaleSet { - scale: ColorScaleName::Pink, + scale: "Pink", light: [ "#fffcfeff", "#fef7fbff", @@ -1123,11 +1403,12 @@ fn pink() -> DefaultColorScaleSet { "#ffd3ecfd", ], } + .into() } -fn plum() -> DefaultColorScaleSet { +fn plum() -> ColorScaleSet { DefaultColorScaleSet { - scale: ColorScaleName::Plum, + scale: "Plum", light: [ "#fefcffff", "#fdf7fdff", @@ -1185,11 +1466,12 @@ fn plum() -> DefaultColorScaleSet { "#feddfef4", ], } + .into() } -fn purple() -> DefaultColorScaleSet { +fn purple() -> ColorScaleSet { DefaultColorScaleSet { - scale: ColorScaleName::Purple, + scale: "Purple", light: [ "#fefcfeff", "#fbf7feff", @@ -1247,11 +1529,12 @@ fn purple() -> DefaultColorScaleSet { "#f1ddfffa", ], } + .into() } -fn violet() -> DefaultColorScaleSet { +fn violet() -> ColorScaleSet { DefaultColorScaleSet { - scale: ColorScaleName::Violet, + scale: "Violet", light: [ "#fdfcfeff", "#faf8ffff", @@ -1309,11 +1592,12 @@ fn violet() -> DefaultColorScaleSet { "#e3defffe", ], } + .into() } -fn iris() -> DefaultColorScaleSet { +fn iris() -> ColorScaleSet { DefaultColorScaleSet { - scale: ColorScaleName::Iris, + scale: "Iris", light: [ "#fdfdffff", "#f8f8ffff", @@ -1371,11 +1655,12 @@ fn iris() -> DefaultColorScaleSet { "#e1e0fffe", ], } + .into() } -fn indigo() -> DefaultColorScaleSet { +fn indigo() -> ColorScaleSet { DefaultColorScaleSet { - scale: ColorScaleName::Indigo, + scale: "Indigo", light: [ "#fdfdfeff", "#f7f9ffff", @@ -1433,11 +1718,12 @@ fn indigo() -> DefaultColorScaleSet { "#d6e1ffff", ], } + .into() } -fn blue() -> DefaultColorScaleSet { +fn blue() -> ColorScaleSet { DefaultColorScaleSet { - scale: ColorScaleName::Blue, + scale: "Blue", light: [ "#fbfdffff", "#f4faffff", @@ -1495,11 +1781,12 @@ fn blue() -> DefaultColorScaleSet { "#c2e6ffff", ], } + .into() } -fn cyan() -> DefaultColorScaleSet { +fn cyan() -> ColorScaleSet { DefaultColorScaleSet { - scale: ColorScaleName::Cyan, + scale: "Cyan", light: [ "#fafdfeff", "#f2fafbff", @@ -1557,11 +1844,12 @@ fn cyan() -> DefaultColorScaleSet { "#bbf3fef7", ], } + .into() } -fn teal() -> DefaultColorScaleSet { +fn teal() -> ColorScaleSet { DefaultColorScaleSet { - scale: ColorScaleName::Teal, + scale: "Teal", light: [ "#fafefdff", "#f3fbf9ff", @@ -1619,11 +1907,12 @@ fn teal() -> DefaultColorScaleSet { "#b8ffebef", ], } + .into() } -fn jade() -> DefaultColorScaleSet { +fn jade() -> ColorScaleSet { DefaultColorScaleSet { - scale: ColorScaleName::Jade, + scale: "Jade", light: [ "#fbfefdff", "#f4fbf7ff", @@ -1681,11 +1970,12 @@ fn jade() -> DefaultColorScaleSet { "#b8ffe1ef", ], } + .into() } -fn green() -> DefaultColorScaleSet { +fn green() -> ColorScaleSet { DefaultColorScaleSet { - scale: ColorScaleName::Green, + scale: "Green", light: [ "#fbfefcff", "#f4fbf6ff", @@ -1743,11 +2033,12 @@ fn green() -> DefaultColorScaleSet { "#bbffd7f0", ], } + .into() } -fn grass() -> DefaultColorScaleSet { +fn grass() -> ColorScaleSet { DefaultColorScaleSet { - scale: ColorScaleName::Grass, + scale: "Grass", light: [ "#fbfefbff", "#f5fbf5ff", @@ -1805,11 +2096,12 @@ fn grass() -> DefaultColorScaleSet { "#ceffceef", ], } + .into() } -fn lime() -> DefaultColorScaleSet { +fn lime() -> ColorScaleSet { DefaultColorScaleSet { - scale: ColorScaleName::Lime, + scale: "Lime", light: [ "#fcfdfaff", "#f8faf3ff", @@ -1867,11 +2159,12 @@ fn lime() -> DefaultColorScaleSet { "#e9febff7", ], } + .into() } -fn mint() -> DefaultColorScaleSet { +fn mint() -> ColorScaleSet { DefaultColorScaleSet { - scale: ColorScaleName::Mint, + scale: "Mint", light: [ "#f9fefdff", "#f2fbf9ff", @@ -1929,11 +2222,12 @@ fn mint() -> DefaultColorScaleSet { "#cbfee9f5", ], } + .into() } -fn sky() -> DefaultColorScaleSet { +fn sky() -> ColorScaleSet { DefaultColorScaleSet { - scale: ColorScaleName::Sky, + scale: "Sky", light: [ "#f9feffff", "#f1fafdff", @@ -1991,11 +2285,12 @@ fn sky() -> DefaultColorScaleSet { "#c2f3ffff", ], } + .into() } -fn black() -> DefaultColorScaleSet { +fn black() -> ColorScaleSet { DefaultColorScaleSet { - scale: ColorScaleName::Black, + scale: "Black", light: [ "#0000000d", "#0000001a", @@ -2053,11 +2348,12 @@ fn black() -> DefaultColorScaleSet { "#000000f2", ], } + .into() } -fn white() -> DefaultColorScaleSet { +fn white() -> ColorScaleSet { DefaultColorScaleSet { - scale: ColorScaleName::White, + scale: "White", light: [ "#ffffff0d", "#ffffff1a", @@ -2115,4 +2411,5 @@ fn white() -> DefaultColorScaleSet { "#fffffff2", ], } + .into() } diff --git a/crates/theme2/src/default_theme.rs b/crates/theme2/src/default_theme.rs new file mode 100644 index 0000000000..d7360b6f71 --- /dev/null +++ b/crates/theme2/src/default_theme.rs @@ -0,0 +1,58 @@ +use crate::{ + colors::{GitStatusColors, PlayerColors, StatusColors, SystemColors, ThemeColors, ThemeStyles}, + default_color_scales, Appearance, SyntaxTheme, ThemeFamily, ThemeVariant, +}; + +fn zed_pro_daylight() -> ThemeVariant { + ThemeVariant { + id: "zed_pro_daylight".to_string(), + name: "Zed Pro Daylight".into(), + appearance: Appearance::Light, + styles: ThemeStyles { + system: SystemColors::default(), + colors: ThemeColors::default_light(), + status: StatusColors::default(), + git: GitStatusColors::default(), + player: PlayerColors::default(), + syntax: SyntaxTheme::default_light(), + }, + } +} + +pub(crate) fn zed_pro_moonlight() -> ThemeVariant { + ThemeVariant { + id: "zed_pro_moonlight".to_string(), + name: "Zed Pro Moonlight".into(), + appearance: Appearance::Dark, + styles: ThemeStyles { + system: SystemColors::default(), + colors: ThemeColors::default_dark(), + status: StatusColors::default(), + git: GitStatusColors::default(), + player: PlayerColors::default(), + syntax: SyntaxTheme::default_dark(), + }, + } +} + +pub fn zed_pro_family() -> ThemeFamily { + ThemeFamily { + id: "zed_pro".to_string(), + name: "Zed Pro".into(), + author: "Zed Team".into(), + themes: vec![zed_pro_daylight(), zed_pro_moonlight()], + scales: default_color_scales(), + } +} + +impl Default for ThemeFamily { + fn default() -> Self { + zed_pro_family() + } +} + +impl Default for ThemeVariant { + fn default() -> Self { + zed_pro_daylight() + } +} diff --git a/crates/theme2/src/registry.rs b/crates/theme2/src/registry.rs index eec82ef5a7..f30f5ead91 100644 --- a/crates/theme2/src/registry.rs +++ b/crates/theme2/src/registry.rs @@ -1,17 +1,22 @@ -use crate::{themes, Theme, ThemeMetadata}; +use crate::{zed_pro_family, ThemeFamily, ThemeVariant}; use anyhow::{anyhow, Result}; use gpui2::SharedString; use std::{collections::HashMap, sync::Arc}; pub struct ThemeRegistry { - themes: HashMap>, + themes: HashMap>, } impl ThemeRegistry { - fn insert_themes(&mut self, themes: impl IntoIterator) { + fn insert_theme_families(&mut self, families: impl IntoIterator) { + for family in families.into_iter() { + self.insert_themes(family.themes); + } + } + + fn insert_themes(&mut self, themes: impl IntoIterator) { for theme in themes.into_iter() { - self.themes - .insert(theme.metadata.name.clone(), Arc::new(theme)); + self.themes.insert(theme.name.clone(), Arc::new(theme)); } } @@ -19,11 +24,11 @@ impl ThemeRegistry { self.themes.keys().cloned() } - pub fn list(&self, _staff: bool) -> impl Iterator + '_ { - self.themes.values().map(|theme| theme.metadata.clone()) + pub fn list(&self, _staff: bool) -> impl Iterator + '_ { + self.themes.values().map(|theme| theme.name.clone()) } - pub fn get(&self, name: &str) -> Result> { + pub fn get(&self, name: &str) -> Result> { self.themes .get(name) .ok_or_else(|| anyhow!("theme not found: {}", name)) @@ -37,47 +42,7 @@ impl Default for ThemeRegistry { themes: HashMap::default(), }; - this.insert_themes([ - 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.insert_theme_families([zed_pro_family()]); this } diff --git a/crates/theme2/src/scale.rs b/crates/theme2/src/scale.rs index 22a607bf07..21c8592d81 100644 --- a/crates/theme2/src/scale.rs +++ b/crates/theme2/src/scale.rs @@ -1,98 +1,95 @@ -use gpui2::{AppContext, Hsla}; -use indexmap::IndexMap; +use gpui2::{AppContext, Hsla, SharedString}; -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", - } - ) - } -} +use crate::{ActiveTheme, Appearance}; pub type ColorScale = [Hsla; 12]; -pub type ColorScales = IndexMap; +pub struct ColorScales { + pub gray: ColorScaleSet, + pub mauve: ColorScaleSet, + pub slate: ColorScaleSet, + pub sage: ColorScaleSet, + pub olive: ColorScaleSet, + pub sand: ColorScaleSet, + pub gold: ColorScaleSet, + pub bronze: ColorScaleSet, + pub brown: ColorScaleSet, + pub yellow: ColorScaleSet, + pub amber: ColorScaleSet, + pub orange: ColorScaleSet, + pub tomato: ColorScaleSet, + pub red: ColorScaleSet, + pub ruby: ColorScaleSet, + pub crimson: ColorScaleSet, + pub pink: ColorScaleSet, + pub plum: ColorScaleSet, + pub purple: ColorScaleSet, + pub violet: ColorScaleSet, + pub iris: ColorScaleSet, + pub indigo: ColorScaleSet, + pub blue: ColorScaleSet, + pub cyan: ColorScaleSet, + pub teal: ColorScaleSet, + pub jade: ColorScaleSet, + pub green: ColorScaleSet, + pub grass: ColorScaleSet, + pub lime: ColorScaleSet, + pub mint: ColorScaleSet, + pub sky: ColorScaleSet, + pub black: ColorScaleSet, + pub white: ColorScaleSet, +} + +impl IntoIterator for ColorScales { + type Item = ColorScaleSet; + + type IntoIter = std::vec::IntoIter; + + fn into_iter(self) -> Self::IntoIter { + vec![ + self.gray, + self.mauve, + self.slate, + self.sage, + self.olive, + self.sand, + self.gold, + self.bronze, + self.brown, + self.yellow, + self.amber, + self.orange, + self.tomato, + self.red, + self.ruby, + self.crimson, + self.pink, + self.plum, + self.purple, + self.violet, + self.iris, + self.indigo, + self.blue, + self.cyan, + self.teal, + self.jade, + self.green, + self.grass, + self.lime, + self.mint, + self.sky, + self.black, + self.white, + ] + .into_iter() + } +} /// A one-based step in a [`ColorScale`]. pub type ColorScaleStep = usize; pub struct ColorScaleSet { - name: ColorScaleName, + name: SharedString, light: ColorScale, dark: ColorScale, light_alpha: ColorScale, @@ -101,14 +98,14 @@ pub struct ColorScaleSet { impl ColorScaleSet { pub fn new( - name: ColorScaleName, + name: impl Into, light: ColorScale, light_alpha: ColorScale, dark: ColorScale, dark_alpha: ColorScale, ) -> Self { Self { - name, + name: name.into(), light, light_alpha, dark, @@ -116,8 +113,8 @@ impl ColorScaleSet { } } - pub fn name(&self) -> String { - self.name.to_string() + pub fn name(&self) -> &SharedString { + &self.name } pub fn light(&self, step: ColorScaleStep) -> Hsla { @@ -136,27 +133,15 @@ impl ColorScaleSet { 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 { + match cx.theme().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 { + match cx.theme().appearance { Appearance::Light => self.light_alpha(step), Appearance::Dark => self.dark_alpha(step), } diff --git a/crates/theme2/src/settings.rs b/crates/theme2/src/settings.rs index 379b01dd4b..c8d2b52273 100644 --- a/crates/theme2/src/settings.rs +++ b/crates/theme2/src/settings.rs @@ -1,4 +1,4 @@ -use crate::{Theme, ThemeRegistry}; +use crate::{ThemeRegistry, ThemeVariant}; use anyhow::Result; use gpui2::{px, AppContext, Font, FontFeatures, FontStyle, FontWeight, Pixels}; use schemars::{ @@ -17,10 +17,11 @@ const MIN_LINE_HEIGHT: f32 = 1.0; #[derive(Clone)] pub struct ThemeSettings { + pub ui_font_size: Pixels, pub buffer_font: Font, pub buffer_font_size: Pixels, pub buffer_line_height: BufferLineHeight, - pub active_theme: Arc, + pub active_theme: Arc, } #[derive(Default)] @@ -28,6 +29,8 @@ pub struct AdjustedBufferFontSize(Option); #[derive(Clone, Debug, Default, Serialize, Deserialize, JsonSchema)] pub struct ThemeSettingsContent { + #[serde(default)] + pub ui_font_size: Option, #[serde(default)] pub buffer_font_family: Option, #[serde(default)] @@ -115,6 +118,7 @@ impl settings2::Settings for ThemeSettings { let themes = cx.default_global::>(); let mut this = Self { + ui_font_size: defaults.ui_font_size.unwrap_or(16.).into(), buffer_font: Font { family: defaults.buffer_font_family.clone().unwrap().into(), features: defaults.buffer_font_features.clone().unwrap(), @@ -123,7 +127,10 @@ impl settings2::Settings for ThemeSettings { }, buffer_font_size: defaults.buffer_font_size.unwrap().into(), buffer_line_height: defaults.buffer_line_height.unwrap(), - active_theme: themes.get(defaults.theme.as_ref().unwrap()).unwrap(), + active_theme: themes + .get(defaults.theme.as_ref().unwrap()) + .or(themes.get("Zed Pro Moonlight")) + .unwrap(), }; for value in user_values.into_iter().copied().cloned() { @@ -140,6 +147,7 @@ impl settings2::Settings for ThemeSettings { } } + merge(&mut this.ui_font_size, value.ui_font_size.map(Into::into)); merge( &mut this.buffer_font_size, value.buffer_font_size.map(Into::into), diff --git a/crates/theme2/src/syntax.rs b/crates/theme2/src/syntax.rs new file mode 100644 index 0000000000..a8127f0c44 --- /dev/null +++ b/crates/theme2/src/syntax.rs @@ -0,0 +1,37 @@ +use gpui2::{HighlightStyle, Hsla}; + +#[derive(Clone, Default)] +pub struct SyntaxTheme { + pub highlights: Vec<(String, HighlightStyle)>, +} + +impl SyntaxTheme { + // TOOD: Get this working with `#[cfg(test)]`. Why isn't it? + pub fn new_test(colors: impl IntoIterator) -> Self { + SyntaxTheme { + highlights: colors + .into_iter() + .map(|(key, color)| { + ( + key.to_owned(), + HighlightStyle { + color: Some(color), + ..Default::default() + }, + ) + }) + .collect(), + } + } + + pub fn get(&self, name: &str) -> HighlightStyle { + self.highlights + .iter() + .find_map(|entry| if entry.0 == name { Some(entry.1) } else { None }) + .unwrap_or_default() + } + + pub fn color(&self, name: &str) -> Hsla { + self.get(name).color.unwrap_or_default() + } +} diff --git a/crates/theme2/src/theme2.rs b/crates/theme2/src/theme2.rs index b96a23c338..34727eaf89 100644 --- a/crates/theme2/src/theme2.rs +++ b/crates/theme2/src/theme2.rs @@ -1,17 +1,21 @@ -mod default; +mod colors; +mod default_colors; +mod default_theme; mod registry; mod scale; mod settings; -mod themes; +mod syntax; -pub use default::*; +pub use colors::*; +pub use default_colors::*; +pub use default_theme::*; pub use registry::*; pub use scale::*; pub use settings::*; +pub use syntax::*; -use gpui2::{AppContext, HighlightStyle, Hsla, SharedString}; +use gpui2::{AppContext, Hsla, SharedString}; use settings2::Settings; -use std::sync::Arc; #[derive(Debug, Clone, PartialEq)] pub enum Appearance { @@ -24,132 +28,51 @@ pub fn init(cx: &mut AppContext) { ThemeSettings::register(cx); } -pub fn active_theme<'a>(cx: &'a AppContext) -> &'a Arc { - &ThemeSettings::get_global(cx).active_theme +pub trait ActiveTheme { + fn theme(&self) -> &ThemeVariant; } -pub fn theme(cx: &AppContext) -> Arc { - active_theme(cx).clone() -} - -pub struct Theme { - pub metadata: ThemeMetadata, - - pub transparent: Hsla, - pub mac_os_traffic_light_red: Hsla, - pub mac_os_traffic_light_yellow: Hsla, - pub mac_os_traffic_light_green: Hsla, - pub border: Hsla, - pub border_variant: Hsla, - pub border_focused: Hsla, - pub border_transparent: Hsla, - /// The background color of an elevated surface, like a modal, tooltip or toast. - pub elevated_surface: Hsla, - pub surface: Hsla, - /// Window background color of the base app - pub background: Hsla, - /// Default background for elements like filled buttons, - /// text fields, checkboxes, radio buttons, etc. - /// - TODO: Map to step 3. - pub filled_element: Hsla, - /// The background color of a hovered element, like a button being hovered - /// with a mouse, or hovered on a touch screen. - /// - TODO: Map to step 4. - pub filled_element_hover: Hsla, - /// The background color of an active element, like a button being pressed, - /// or tapped on a touch screen. - /// - TODO: Map to step 5. - pub filled_element_active: Hsla, - /// The background color of a selected element, like a selected tab, - /// a button toggled on, or a checkbox that is checked. - pub filled_element_selected: Hsla, - pub filled_element_disabled: Hsla, - pub ghost_element: Hsla, - /// The background color of a hovered element with no default background, - /// like a ghost-style button or an interactable list item. - /// - TODO: Map to step 3. - pub ghost_element_hover: Hsla, - /// - TODO: Map to step 4. - pub ghost_element_active: Hsla, - pub ghost_element_selected: Hsla, - pub ghost_element_disabled: Hsla, - pub text: Hsla, - pub text_muted: Hsla, - pub text_placeholder: Hsla, - pub text_disabled: Hsla, - pub text_accent: Hsla, - pub icon_muted: Hsla, - pub syntax: SyntaxTheme, - - pub status_bar: Hsla, - pub title_bar: Hsla, - pub toolbar: Hsla, - pub tab_bar: Hsla, - /// The background of the editor - pub editor: Hsla, - pub editor_subheader: Hsla, - pub editor_active_line: Hsla, - pub terminal: Hsla, - pub image_fallback_background: Hsla, - - pub git_created: Hsla, - pub git_modified: Hsla, - pub git_deleted: Hsla, - pub git_conflict: Hsla, - pub git_ignored: Hsla, - pub git_renamed: Hsla, - - pub players: [PlayerTheme; 8], -} - -#[derive(Clone)] -pub struct SyntaxTheme { - pub highlights: Vec<(String, HighlightStyle)>, -} - -impl SyntaxTheme { - // TOOD: Get this working with `#[cfg(test)]`. Why isn't it? - pub fn new_test(colors: impl IntoIterator) -> Self { - SyntaxTheme { - highlights: colors - .into_iter() - .map(|(key, color)| { - ( - key.to_owned(), - HighlightStyle { - color: Some(color), - ..Default::default() - }, - ) - }) - .collect(), - } - } - - pub fn get(&self, name: &str) -> HighlightStyle { - self.highlights - .iter() - .find_map(|entry| if entry.0 == name { Some(entry.1) } else { None }) - .unwrap_or_default() - } - - pub fn color(&self, name: &str) -> Hsla { - self.get(name).color.unwrap_or_default() +impl ActiveTheme for AppContext { + fn theme(&self) -> &ThemeVariant { + &ThemeSettings::get_global(self).active_theme } } -#[derive(Clone, Copy)] -pub struct PlayerTheme { - pub cursor: Hsla, - pub selection: Hsla, -} - -#[derive(Clone)] -pub struct ThemeMetadata { +pub struct ThemeFamily { + #[allow(dead_code)] + pub(crate) id: String, pub name: SharedString, - pub is_light: bool, + pub author: SharedString, + pub themes: Vec, + pub scales: ColorScales, } -pub struct Editor { - pub syntax: Arc, +impl ThemeFamily {} + +pub struct ThemeVariant { + #[allow(dead_code)] + pub(crate) id: String, + pub name: SharedString, + pub appearance: Appearance, + pub styles: ThemeStyles, +} + +impl ThemeVariant { + /// Returns the [`ThemeColors`] for the theme. + #[inline(always)] + pub fn colors(&self) -> &ThemeColors { + &self.styles.colors + } + + /// Returns the [`SyntaxTheme`] for the theme. + #[inline(always)] + pub fn syntax(&self) -> &SyntaxTheme { + &self.styles.syntax + } + + /// Returns the color for the syntax node with the given name. + #[inline(always)] + pub fn syntax_color(&self, name: &str) -> Hsla { + self.syntax().color(name) + } } diff --git a/crates/theme2/src/themes/andromeda.rs b/crates/theme2/src/themes/andromeda.rs deleted file mode 100644 index 6afd7edd4d..0000000000 --- a/crates/theme2/src/themes/andromeda.rs +++ /dev/null @@ -1,130 +0,0 @@ -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 deleted file mode 100644 index c5190f4e98..0000000000 --- a/crates/theme2/src/themes/atelier_cave_dark.rs +++ /dev/null @@ -1,136 +0,0 @@ -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 deleted file mode 100644 index ae2e912f14..0000000000 --- a/crates/theme2/src/themes/atelier_cave_light.rs +++ /dev/null @@ -1,136 +0,0 @@ -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 deleted file mode 100644 index 03d0c5eea0..0000000000 --- a/crates/theme2/src/themes/atelier_dune_dark.rs +++ /dev/null @@ -1,136 +0,0 @@ -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 deleted file mode 100644 index 1d0f944916..0000000000 --- a/crates/theme2/src/themes/atelier_dune_light.rs +++ /dev/null @@ -1,136 +0,0 @@ -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 deleted file mode 100644 index ad5c9fbc1e..0000000000 --- a/crates/theme2/src/themes/atelier_estuary_dark.rs +++ /dev/null @@ -1,136 +0,0 @@ -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 deleted file mode 100644 index 91eaa88fab..0000000000 --- a/crates/theme2/src/themes/atelier_estuary_light.rs +++ /dev/null @@ -1,136 +0,0 @@ -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 deleted file mode 100644 index 83228e671f..0000000000 --- a/crates/theme2/src/themes/atelier_forest_dark.rs +++ /dev/null @@ -1,136 +0,0 @@ -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 deleted file mode 100644 index 882d5c2fcb..0000000000 --- a/crates/theme2/src/themes/atelier_forest_light.rs +++ /dev/null @@ -1,136 +0,0 @@ -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 deleted file mode 100644 index 354c98069f..0000000000 --- a/crates/theme2/src/themes/atelier_heath_dark.rs +++ /dev/null @@ -1,136 +0,0 @@ -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 deleted file mode 100644 index f1a9e4d8c6..0000000000 --- a/crates/theme2/src/themes/atelier_heath_light.rs +++ /dev/null @@ -1,136 +0,0 @@ -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 deleted file mode 100644 index 61b78864b7..0000000000 --- a/crates/theme2/src/themes/atelier_lakeside_dark.rs +++ /dev/null @@ -1,136 +0,0 @@ -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 deleted file mode 100644 index 64fb70dadb..0000000000 --- a/crates/theme2/src/themes/atelier_lakeside_light.rs +++ /dev/null @@ -1,136 +0,0 @@ -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 deleted file mode 100644 index 0ba5a1659d..0000000000 --- a/crates/theme2/src/themes/atelier_plateau_dark.rs +++ /dev/null @@ -1,136 +0,0 @@ -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 deleted file mode 100644 index 68f100dd85..0000000000 --- a/crates/theme2/src/themes/atelier_plateau_light.rs +++ /dev/null @@ -1,136 +0,0 @@ -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 deleted file mode 100644 index d4040db958..0000000000 --- a/crates/theme2/src/themes/atelier_savanna_dark.rs +++ /dev/null @@ -1,136 +0,0 @@ -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 deleted file mode 100644 index 08722cd91c..0000000000 --- a/crates/theme2/src/themes/atelier_savanna_light.rs +++ /dev/null @@ -1,136 +0,0 @@ -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 deleted file mode 100644 index 475115e0d1..0000000000 --- a/crates/theme2/src/themes/atelier_seaside_dark.rs +++ /dev/null @@ -1,136 +0,0 @@ -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 deleted file mode 100644 index 557134b540..0000000000 --- a/crates/theme2/src/themes/atelier_seaside_light.rs +++ /dev/null @@ -1,136 +0,0 @@ -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 deleted file mode 100644 index 8be8451740..0000000000 --- a/crates/theme2/src/themes/atelier_sulphurpool_dark.rs +++ /dev/null @@ -1,136 +0,0 @@ -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 deleted file mode 100644 index dba723331a..0000000000 --- a/crates/theme2/src/themes/atelier_sulphurpool_light.rs +++ /dev/null @@ -1,136 +0,0 @@ -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 deleted file mode 100644 index 35d3a43154..0000000000 --- a/crates/theme2/src/themes/ayu_dark.rs +++ /dev/null @@ -1,130 +0,0 @@ -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 deleted file mode 100644 index 887282e564..0000000000 --- a/crates/theme2/src/themes/ayu_light.rs +++ /dev/null @@ -1,130 +0,0 @@ -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 deleted file mode 100644 index 2974881a18..0000000000 --- a/crates/theme2/src/themes/ayu_mirage.rs +++ /dev/null @@ -1,130 +0,0 @@ -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 deleted file mode 100644 index 6e982808cf..0000000000 --- a/crates/theme2/src/themes/gruvbox_dark.rs +++ /dev/null @@ -1,131 +0,0 @@ -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 deleted file mode 100644 index 159ab28325..0000000000 --- a/crates/theme2/src/themes/gruvbox_dark_hard.rs +++ /dev/null @@ -1,131 +0,0 @@ -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 deleted file mode 100644 index 6a6423389e..0000000000 --- a/crates/theme2/src/themes/gruvbox_dark_soft.rs +++ /dev/null @@ -1,131 +0,0 @@ -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 deleted file mode 100644 index 7582f8bd8a..0000000000 --- a/crates/theme2/src/themes/gruvbox_light.rs +++ /dev/null @@ -1,131 +0,0 @@ -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 deleted file mode 100644 index e5e3fe54cf..0000000000 --- a/crates/theme2/src/themes/gruvbox_light_hard.rs +++ /dev/null @@ -1,131 +0,0 @@ -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 deleted file mode 100644 index 15574e2960..0000000000 --- a/crates/theme2/src/themes/gruvbox_light_soft.rs +++ /dev/null @@ -1,131 +0,0 @@ -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 deleted file mode 100644 index 17cd5ac6e0..0000000000 --- a/crates/theme2/src/themes/mod.rs +++ /dev/null @@ -1,79 +0,0 @@ -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 deleted file mode 100644 index c7408d1820..0000000000 --- a/crates/theme2/src/themes/one_dark.rs +++ /dev/null @@ -1,131 +0,0 @@ -use gpui2::rgba; - -use crate::{PlayerTheme, SyntaxTheme, Theme, ThemeMetadata}; - -pub fn one_dark() -> Theme { - Theme { - metadata: ThemeMetadata { - name: "One 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(0x464b57ff).into(), - border_variant: rgba(0x464b57ff).into(), - border_focused: rgba(0x293b5bff).into(), - border_transparent: rgba(0x00000000).into(), - elevated_surface: rgba(0x3b414dff).into(), - surface: rgba(0x2f343eff).into(), - background: rgba(0x3b414dff).into(), - filled_element: rgba(0x3b414dff).into(), - filled_element_hover: rgba(0xffffff1e).into(), - filled_element_active: rgba(0xffffff28).into(), - filled_element_selected: rgba(0x18243dff).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(0x18243dff).into(), - ghost_element_disabled: rgba(0x00000000).into(), - text: rgba(0xc8ccd4ff).into(), - text_muted: rgba(0x838994ff).into(), - text_placeholder: rgba(0xd07277ff).into(), - text_disabled: rgba(0x555a63ff).into(), - text_accent: rgba(0x74ade8ff).into(), - icon_muted: rgba(0x838994ff).into(), - syntax: SyntaxTheme { - highlights: vec![ - ("keyword".into(), rgba(0xb477cfff).into()), - ("comment.doc".into(), rgba(0x878e98ff).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()), - ("string.escape".into(), rgba(0x878e98ff).into()), - ("punctuation.bracket".into(), rgba(0xb2b9c6ff).into()), - ("hint".into(), rgba(0x5a6f89ff).into()), - ("punctuation".into(), rgba(0xacb2beff).into()), - ("comment".into(), rgba(0x5d636fff).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(), - title_bar: rgba(0x3b414dff).into(), - toolbar: rgba(0x282c33ff).into(), - tab_bar: rgba(0x2f343eff).into(), - editor: rgba(0x282c33ff).into(), - editor_subheader: rgba(0x2f343eff).into(), - editor_active_line: rgba(0x2f343eff).into(), - terminal: rgba(0x282c33ff).into(), - image_fallback_background: rgba(0x3b414dff).into(), - git_created: rgba(0xa1c181ff).into(), - git_modified: rgba(0x74ade8ff).into(), - git_deleted: rgba(0xd07277ff).into(), - git_conflict: rgba(0xdec184ff).into(), - git_ignored: rgba(0x555a63ff).into(), - git_renamed: rgba(0xdec184ff).into(), - players: [ - PlayerTheme { - cursor: rgba(0x74ade8ff).into(), - selection: rgba(0x74ade83d).into(), - }, - PlayerTheme { - cursor: rgba(0xa1c181ff).into(), - selection: rgba(0xa1c1813d).into(), - }, - PlayerTheme { - cursor: rgba(0xbe5046ff).into(), - selection: rgba(0xbe50463d).into(), - }, - PlayerTheme { - cursor: rgba(0xbf956aff).into(), - selection: rgba(0xbf956a3d).into(), - }, - PlayerTheme { - cursor: rgba(0xb477cfff).into(), - selection: rgba(0xb477cf3d).into(), - }, - PlayerTheme { - cursor: rgba(0x6eb4bfff).into(), - selection: rgba(0x6eb4bf3d).into(), - }, - PlayerTheme { - cursor: rgba(0xd07277ff).into(), - selection: rgba(0xd072773d).into(), - }, - PlayerTheme { - cursor: rgba(0xdec184ff).into(), - selection: rgba(0xdec1843d).into(), - }, - ], - } -} diff --git a/crates/theme2/src/themes/one_light.rs b/crates/theme2/src/themes/one_light.rs deleted file mode 100644 index ee802d57d3..0000000000 --- a/crates/theme2/src/themes/one_light.rs +++ /dev/null @@ -1,131 +0,0 @@ -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 deleted file mode 100644 index f3bd454cdc..0000000000 --- a/crates/theme2/src/themes/rose_pine.rs +++ /dev/null @@ -1,132 +0,0 @@ -use gpui2::rgba; - -use crate::{PlayerTheme, SyntaxTheme, Theme, ThemeMetadata}; - -pub fn rose_pine() -> Theme { - Theme { - metadata: ThemeMetadata { - name: "Rosé Pine".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(0x423f55ff).into(), - border_variant: rgba(0x423f55ff).into(), - border_focused: rgba(0x435255ff).into(), - border_transparent: rgba(0x00000000).into(), - elevated_surface: rgba(0x292738ff).into(), - surface: rgba(0x1c1b2aff).into(), - background: rgba(0x292738ff).into(), - filled_element: rgba(0x292738ff).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(0x74708dff).into(), - text_placeholder: rgba(0xea6e92ff).into(), - text_disabled: rgba(0x2f2b43ff).into(), - text_accent: rgba(0x9bced6ff).into(), - icon_muted: rgba(0x74708dff).into(), - syntax: SyntaxTheme { - highlights: vec![ - ("punctuation.delimiter".into(), rgba(0x9d99b6ff).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(), - title_bar: rgba(0x292738ff).into(), - toolbar: rgba(0x191724ff).into(), - tab_bar: rgba(0x1c1b2aff).into(), - editor: rgba(0x191724ff).into(), - editor_subheader: rgba(0x1c1b2aff).into(), - editor_active_line: rgba(0x1c1b2aff).into(), - terminal: rgba(0x191724ff).into(), - image_fallback_background: rgba(0x292738ff).into(), - git_created: rgba(0x5cc1a3ff).into(), - git_modified: rgba(0x9bced6ff).into(), - git_deleted: rgba(0xea6e92ff).into(), - git_conflict: rgba(0xf5c177ff).into(), - git_ignored: rgba(0x2f2b43ff).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(0x9d7591ff).into(), - selection: rgba(0x9d75913d).into(), - }, - PlayerTheme { - cursor: rgba(0xc4a7e6ff).into(), - selection: rgba(0xc4a7e63d).into(), - }, - PlayerTheme { - cursor: rgba(0xc4a7e6ff).into(), - selection: rgba(0xc4a7e63d).into(), - }, - PlayerTheme { - cursor: rgba(0x31738fff).into(), - selection: rgba(0x31738f3d).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 deleted file mode 100644 index ba64bf9d99..0000000000 --- a/crates/theme2/src/themes/rose_pine_dawn.rs +++ /dev/null @@ -1,132 +0,0 @@ -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 deleted file mode 100644 index 167b78afb5..0000000000 --- a/crates/theme2/src/themes/rose_pine_moon.rs +++ /dev/null @@ -1,132 +0,0 @@ -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 deleted file mode 100644 index 7fa0a27fb3..0000000000 --- a/crates/theme2/src/themes/sandcastle.rs +++ /dev/null @@ -1,130 +0,0 @@ -use gpui2::rgba; - -use crate::{PlayerTheme, SyntaxTheme, Theme, ThemeMetadata}; - -pub fn sandcastle() -> Theme { - Theme { - metadata: ThemeMetadata { - name: "Sandcastle".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(0x3d4350ff).into(), - border_variant: rgba(0x3d4350ff).into(), - border_focused: rgba(0x223131ff).into(), - border_transparent: rgba(0x00000000).into(), - elevated_surface: rgba(0x333944ff).into(), - surface: rgba(0x2b3038ff).into(), - background: rgba(0x333944ff).into(), - filled_element: rgba(0x333944ff).into(), - filled_element_hover: rgba(0xffffff1e).into(), - filled_element_active: rgba(0xffffff28).into(), - filled_element_selected: rgba(0x171e1eff).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(0x171e1eff).into(), - ghost_element_disabled: rgba(0x00000000).into(), - text: rgba(0xfdf4c1ff).into(), - text_muted: rgba(0xa69782ff).into(), - text_placeholder: rgba(0xb3627aff).into(), - text_disabled: rgba(0x827568ff).into(), - text_accent: rgba(0x518b8bff).into(), - icon_muted: rgba(0xa69782ff).into(), - syntax: SyntaxTheme { - highlights: vec![ - ("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()), - ("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()), - ("punctuation.special".into(), rgba(0xd5c5a1ff).into()), - ("keyword".into(), rgba(0x518b8bff).into()), - ("constructor".into(), rgba(0x518b8bff).into()), - ("predictive".into(), rgba(0x5c6152ff).into()), - ("title".into(), rgba(0xfdf4c1ff).into()), - ("variable".into(), rgba(0xfdf4c1ff).into()), - ("emphasis.strong".into(), rgba(0x518b8bff).into()), - ("primary".into(), rgba(0xfdf4c1ff).into()), - ("emphasis".into(), rgba(0x518b8bff).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(), - title_bar: rgba(0x333944ff).into(), - toolbar: rgba(0x282c33ff).into(), - tab_bar: rgba(0x2b3038ff).into(), - editor: rgba(0x282c33ff).into(), - editor_subheader: rgba(0x2b3038ff).into(), - editor_active_line: rgba(0x2b3038ff).into(), - terminal: rgba(0x282c33ff).into(), - image_fallback_background: rgba(0x333944ff).into(), - git_created: rgba(0x83a598ff).into(), - git_modified: rgba(0x518b8bff).into(), - git_deleted: rgba(0xb3627aff).into(), - git_conflict: rgba(0xa07d3aff).into(), - git_ignored: rgba(0x827568ff).into(), - git_renamed: rgba(0xa07d3aff).into(), - players: [ - PlayerTheme { - cursor: rgba(0x518b8bff).into(), - selection: rgba(0x518b8b3d).into(), - }, - PlayerTheme { - cursor: rgba(0x83a598ff).into(), - selection: rgba(0x83a5983d).into(), - }, - PlayerTheme { - cursor: rgba(0xa87222ff).into(), - selection: rgba(0xa872223d).into(), - }, - PlayerTheme { - cursor: rgba(0xa07d3aff).into(), - selection: rgba(0xa07d3a3d).into(), - }, - PlayerTheme { - cursor: rgba(0xd75f5fff).into(), - selection: rgba(0xd75f5f3d).into(), - }, - PlayerTheme { - cursor: rgba(0x83a598ff).into(), - selection: rgba(0x83a5983d).into(), - }, - PlayerTheme { - cursor: rgba(0xb3627aff).into(), - selection: rgba(0xb3627a3d).into(), - }, - PlayerTheme { - cursor: rgba(0xa07d3aff).into(), - selection: rgba(0xa07d3a3d).into(), - }, - ], - } -} diff --git a/crates/theme2/src/themes/solarized_dark.rs b/crates/theme2/src/themes/solarized_dark.rs deleted file mode 100644 index 2e381a6e95..0000000000 --- a/crates/theme2/src/themes/solarized_dark.rs +++ /dev/null @@ -1,130 +0,0 @@ -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 deleted file mode 100644 index a959a0a9d1..0000000000 --- a/crates/theme2/src/themes/solarized_light.rs +++ /dev/null @@ -1,130 +0,0 @@ -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 deleted file mode 100644 index c1e66aedd1..0000000000 --- a/crates/theme2/src/themes/summercamp.rs +++ /dev/null @@ -1,130 +0,0 @@ -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 deleted file mode 100644 index 0ec692b7cc..0000000000 --- a/crates/theme_converter/Cargo.toml +++ /dev/null @@ -1,18 +0,0 @@ -[package] -name = "theme_converter" -version = "0.1.0" -edition = "2021" -publish = false - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[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 -serde.workspace = true -simplelog = "0.9" -theme2 = { path = "../theme2" } diff --git a/crates/theme_converter/src/main.rs b/crates/theme_converter/src/main.rs deleted file mode 100644 index cc0cdf9c99..0000000000 --- a/crates/theme_converter/src/main.rs +++ /dev/null @@ -1,390 +0,0 @@ -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 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}; - -use crate::theme_printer::ThemePrinter; - -#[derive(Parser)] -#[command(author, version, about, long_about = None)] -struct Args { - /// The name of the theme to convert. - theme: String, -} - -fn main() -> Result<()> { - SimpleLogger::init(LevelFilter::Info, Default::default()).expect("could not initialize logger"); - - // let args = Args::parse(); - - let themes_path = PathBuf::from_str("crates/theme2/src/themes")?; - - let mut theme_modules = Vec::new(); - - 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(()) -} - -#[derive(RustEmbed)] -#[folder = "../../assets"] -#[include = "fonts/**/*"] -#[include = "icons/**/*"] -#[include = "themes/**/*"] -#[include = "sounds/**/*"] -#[include = "*.md"] -#[exclude = "*.DS_Store"] -pub struct Assets; - -impl AssetSource for Assets { - fn load(&self, path: &str) -> Result> { - Self::get(path) - .map(|f| f.data) - .ok_or_else(|| anyhow!("could not find asset at path \"{}\"", path)) - } - - fn list(&self, path: &str) -> Result> { - Ok(Self::iter() - .filter(|p| p.starts_with(path)) - .map(SharedString::from) - .collect()) - } -} - -#[derive(Clone, Copy)] -pub struct PlayerThemeColors { - pub cursor: Hsla, - pub selection: Hsla, -} - -impl PlayerThemeColors { - pub fn new(theme: &LegacyTheme, ix: usize) -> Self { - if ix < theme.players.len() { - Self { - cursor: theme.players[ix].cursor, - selection: theme.players[ix].selection, - } - } else { - Self { - cursor: rgb::(0xff00ff), - selection: rgb::(0xff00ff), - } - } - } -} - -impl From for PlayerTheme { - fn from(value: PlayerThemeColors) -> Self { - Self { - cursor: value.cursor, - selection: value.selection, - } - } -} - -fn convert_theme(json_theme: JsonTheme, legacy_theme: LegacyTheme) -> Result { - let transparent = hsla(0.0, 0.0, 0.0, 0.0); - - let players: [PlayerTheme; 8] = [ - PlayerThemeColors::new(&legacy_theme, 0).into(), - PlayerThemeColors::new(&legacy_theme, 1).into(), - PlayerThemeColors::new(&legacy_theme, 2).into(), - PlayerThemeColors::new(&legacy_theme, 3).into(), - PlayerThemeColors::new(&legacy_theme, 4).into(), - PlayerThemeColors::new(&legacy_theme, 5).into(), - PlayerThemeColors::new(&legacy_theme, 6).into(), - PlayerThemeColors::new(&legacy_theme, 7).into(), - ]; - - let theme = theme2::Theme { - metadata: theme2::ThemeMetadata { - name: legacy_theme.name.clone().into(), - is_light: legacy_theme.is_light, - }, - transparent, - mac_os_traffic_light_red: rgb::(0xEC695E), - mac_os_traffic_light_yellow: rgb::(0xF4BF4F), - mac_os_traffic_light_green: rgb::(0x62C554), - border: legacy_theme.lowest.base.default.border, - border_variant: legacy_theme.lowest.variant.default.border, - border_focused: legacy_theme.lowest.accent.default.border, - border_transparent: transparent, - elevated_surface: legacy_theme.lowest.base.default.background, - surface: legacy_theme.middle.base.default.background, - background: legacy_theme.lowest.base.default.background, - filled_element: legacy_theme.lowest.base.default.background, - filled_element_hover: hsla(0.0, 0.0, 100.0, 0.12), - filled_element_active: hsla(0.0, 0.0, 100.0, 0.16), - filled_element_selected: legacy_theme.lowest.accent.default.background, - filled_element_disabled: transparent, - ghost_element: transparent, - ghost_element_hover: hsla(0.0, 0.0, 100.0, 0.08), - ghost_element_active: hsla(0.0, 0.0, 100.0, 0.12), - ghost_element_selected: legacy_theme.lowest.accent.default.background, - ghost_element_disabled: transparent, - text: legacy_theme.lowest.base.default.foreground, - text_muted: legacy_theme.lowest.variant.default.foreground, - /// TODO: map this to a real value - text_placeholder: legacy_theme.lowest.negative.default.foreground, - text_disabled: legacy_theme.lowest.base.disabled.foreground, - text_accent: legacy_theme.lowest.accent.default.foreground, - icon_muted: legacy_theme.lowest.variant.default.foreground, - syntax: SyntaxTheme { - highlights: json_theme - .editor - .syntax - .iter() - .map(|(token, style)| (token.clone(), style.color.clone().into())) - .collect(), - }, - status_bar: legacy_theme.lowest.base.default.background, - title_bar: legacy_theme.lowest.base.default.background, - toolbar: legacy_theme.highest.base.default.background, - tab_bar: legacy_theme.middle.base.default.background, - editor: legacy_theme.highest.base.default.background, - editor_subheader: legacy_theme.middle.base.default.background, - terminal: legacy_theme.highest.base.default.background, - editor_active_line: legacy_theme.highest.on.default.background, - image_fallback_background: legacy_theme.lowest.base.default.background, - - git_created: legacy_theme.lowest.positive.default.foreground, - git_modified: legacy_theme.lowest.accent.default.foreground, - git_deleted: legacy_theme.lowest.negative.default.foreground, - git_conflict: legacy_theme.lowest.warning.default.foreground, - git_ignored: legacy_theme.lowest.base.disabled.foreground, - git_renamed: legacy_theme.lowest.warning.default.foreground, - - players, - }; - - Ok(theme) -} - -#[derive(Deserialize)] -struct JsonTheme { - pub editor: JsonEditorTheme, - pub base_theme: serde_json::Value, -} - -#[derive(Deserialize)] -struct JsonEditorTheme { - pub syntax: HashMap, -} - -#[derive(Deserialize)] -struct JsonSyntaxStyle { - pub color: Hsla, -} - -/// Loads the [`Theme`] with the given 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")?; - - let legacy_theme: LegacyTheme = serde_json::from_value(json_theme.base_theme.clone()) - .context("failed to parse `base_theme`")?; - - Ok((json_theme, legacy_theme)) -} - -#[derive(Deserialize, Clone, Default, Debug)] -pub struct LegacyTheme { - 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) -} diff --git a/crates/theme_converter/src/theme_printer.rs b/crates/theme_converter/src/theme_printer.rs deleted file mode 100644 index 3a9bdb159b..0000000000 --- a/crates/theme_converter/src/theme_printer.rs +++ /dev/null @@ -1,174 +0,0 @@ -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/Cargo.toml b/crates/ui2/Cargo.toml index 58013e34cd..f11fd652b6 100644 --- a/crates/ui2/Cargo.toml +++ b/crates/ui2/Cargo.toml @@ -10,6 +10,7 @@ chrono = "0.4" gpui2 = { path = "../gpui2" } itertools = { version = "0.11.0", optional = true } serde.workspace = true +settings2 = { path = "../settings2" } smallvec.workspace = true strum = { version = "0.25.0", features = ["derive"] } theme2 = { path = "../theme2" } diff --git a/crates/ui2/src/components/breadcrumb.rs b/crates/ui2/src/components/breadcrumb.rs index 6b2dfe1cce..163dfabfb0 100644 --- a/crates/ui2/src/components/breadcrumb.rs +++ b/crates/ui2/src/components/breadcrumb.rs @@ -19,24 +19,22 @@ impl Breadcrumb { } fn render_separator(&self, cx: &WindowContext) -> Div { - let theme = theme(cx); - - div().child(" › ").text_color(theme.text_muted) + div() + .child(" › ") + .text_color(cx.theme().colors().text_muted) } fn render(self, view_state: &mut V, cx: &mut ViewContext) -> impl Component { - let theme = theme(cx); - let symbols_len = self.symbols.len(); h_stack() .id("breadcrumb") .px_1() .text_sm() - .text_color(theme.text_muted) + .text_color(cx.theme().colors().text_muted) .rounded_md() - .hover(|style| style.bg(theme.ghost_element_hover)) - .active(|style| style.bg(theme.ghost_element_active)) + .hover(|style| style.bg(cx.theme().colors().ghost_element_hover)) + .active(|style| style.bg(cx.theme().colors().ghost_element_active)) .child(self.path.clone().to_str().unwrap().to_string()) .child(if !self.symbols.is_empty() { self.render_separator(cx) @@ -84,8 +82,6 @@ mod stories { type Element = Div; fn render(&mut self, cx: &mut ViewContext) -> Self::Element { - let theme = theme(cx); - Story::container(cx) .child(Story::title_for::<_, Breadcrumb>(cx)) .child(Story::label(cx, "Default")) @@ -95,21 +91,21 @@ mod stories { Symbol(vec![ HighlightedText { text: "impl ".to_string(), - color: theme.syntax.color("keyword"), + color: cx.theme().syntax_color("keyword"), }, HighlightedText { text: "BreadcrumbStory".to_string(), - color: theme.syntax.color("function"), + color: cx.theme().syntax_color("function"), }, ]), Symbol(vec![ HighlightedText { text: "fn ".to_string(), - color: theme.syntax.color("keyword"), + color: cx.theme().syntax_color("keyword"), }, HighlightedText { text: "render".to_string(), - color: theme.syntax.color("function"), + color: cx.theme().syntax_color("function"), }, ]), ], diff --git a/crates/ui2/src/components/buffer.rs b/crates/ui2/src/components/buffer.rs index 33a98b6ea9..2b3db676ce 100644 --- a/crates/ui2/src/components/buffer.rs +++ b/crates/ui2/src/components/buffer.rs @@ -155,18 +155,16 @@ impl Buffer { } fn render_row(row: BufferRow, cx: &WindowContext) -> impl Component { - let theme = theme(cx); - let line_background = if row.current { - theme.editor_active_line + cx.theme().colors().editor_active_line } else { - theme.transparent + cx.theme().styles.system.transparent }; let line_number_color = if row.current { - theme.text + cx.theme().colors().text } else { - theme.syntax.get("comment").color.unwrap_or_default() + cx.theme().syntax_color("comment") }; h_stack() @@ -216,14 +214,13 @@ impl Buffer { } fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { - let theme = theme(cx); let rows = self.render_rows(cx); v_stack() .flex_1() .w_full() .h_full() - .bg(theme.editor) + .bg(cx.theme().colors().editor) .children(rows) } } @@ -246,8 +243,6 @@ mod stories { type Element = Div; fn render(&mut self, cx: &mut ViewContext) -> Self::Element { - let theme = theme(cx); - Story::container(cx) .child(Story::title_for::<_, Buffer>(cx)) .child(Story::label(cx, "Default")) @@ -257,14 +252,14 @@ mod stories { div() .w(rems(64.)) .h_96() - .child(hello_world_rust_buffer_example(&theme)), + .child(hello_world_rust_buffer_example(cx)), ) .child(Story::label(cx, "Hello World (Rust) with Status")) .child( div() .w(rems(64.)) .h_96() - .child(hello_world_rust_buffer_with_status_example(&theme)), + .child(hello_world_rust_buffer_with_status_example(cx)), ) } } diff --git a/crates/ui2/src/components/buffer_search.rs b/crates/ui2/src/components/buffer_search.rs index c5539f0a4a..5d7de1b408 100644 --- a/crates/ui2/src/components/buffer_search.rs +++ b/crates/ui2/src/components/buffer_search.rs @@ -30,9 +30,7 @@ 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( + h_stack().bg(cx.theme().colors().toolbar).p_2().child( h_stack().child(Input::new("Search")).child( IconButton::::new("replace", Icon::Replace) .when(self.is_replace_open, |this| this.color(IconColor::Accent)) diff --git a/crates/ui2/src/components/collab_panel.rs b/crates/ui2/src/components/collab_panel.rs index a8552c0f23..a0e3b55f63 100644 --- a/crates/ui2/src/components/collab_panel.rs +++ b/crates/ui2/src/components/collab_panel.rs @@ -15,27 +15,29 @@ impl CollabPanel { } fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { - let theme = theme(cx); - v_stack() .id(self.id.clone()) .h_full() - .bg(theme.surface) + .bg(cx.theme().colors().surface) .child( v_stack() .id("crdb") .w_full() .overflow_y_scroll() .child( - div().pb_1().border_color(theme.border).border_b().child( - List::new(static_collab_panel_current_call()) - .header( - ListHeader::new("CRDB") - .left_icon(Icon::Hash.into()) - .toggle(ToggleState::Toggled), - ) - .toggle(ToggleState::Toggled), - ), + div() + .pb_1() + .border_color(cx.theme().colors().border) + .border_b() + .child( + List::new(static_collab_panel_current_call()) + .header( + ListHeader::new("CRDB") + .left_icon(Icon::Hash.into()) + .toggle(ToggleState::Toggled), + ) + .toggle(ToggleState::Toggled), + ), ) .child( v_stack().id("channels").py_1().child( @@ -71,13 +73,13 @@ impl CollabPanel { .h_7() .px_2() .border_t() - .border_color(theme.border) + .border_color(cx.theme().colors().border) .flex() .items_center() .child( div() .text_sm() - .text_color(theme.text_placeholder) + .text_color(cx.theme().colors().text_placeholder) .child("Find..."), ), ) diff --git a/crates/ui2/src/components/context_menu.rs b/crates/ui2/src/components/context_menu.rs index 812221036a..8345be1b35 100644 --- a/crates/ui2/src/components/context_menu.rs +++ b/crates/ui2/src/components/context_menu.rs @@ -44,13 +44,11 @@ impl ContextMenu { } fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { - let theme = theme(cx); - v_stack() .flex() - .bg(theme.elevated_surface) + .bg(cx.theme().colors().elevated_surface) .border() - .border_color(theme.border) + .border_color(cx.theme().colors().border) .child( List::new( self.items diff --git a/crates/ui2/src/components/icon_button.rs b/crates/ui2/src/components/icon_button.rs index 980a1c98aa..101c845a76 100644 --- a/crates/ui2/src/components/icon_button.rs +++ b/crates/ui2/src/components/icon_button.rs @@ -1,6 +1,6 @@ use std::sync::Arc; -use gpui2::MouseButton; +use gpui2::{rems, MouseButton}; use crate::{h_stack, prelude::*}; use crate::{ClickHandler, Icon, IconColor, IconElement}; @@ -66,8 +66,6 @@ impl IconButton { } fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { - let theme = theme(cx); - let icon_color = match (self.state, self.color) { (InteractionState::Disabled, _) => IconColor::Disabled, _ => self.color, @@ -75,14 +73,14 @@ impl IconButton { let (bg_color, bg_hover_color, bg_active_color) = match self.variant { ButtonVariant::Filled => ( - theme.filled_element, - theme.filled_element_hover, - theme.filled_element_active, + cx.theme().colors().element, + cx.theme().colors().element_hover, + cx.theme().colors().element_active, ), ButtonVariant::Ghost => ( - theme.ghost_element, - theme.ghost_element_hover, - theme.ghost_element_active, + cx.theme().colors().ghost_element, + cx.theme().colors().ghost_element_hover, + cx.theme().colors().ghost_element_active, ), }; @@ -90,8 +88,8 @@ impl IconButton { .id(self.id.clone()) .justify_center() .rounded_md() - .py(ui_size(cx, 0.25)) - .px(ui_size(cx, 6. / 14.)) + .py(rems(0.21875)) + .px(rems(0.375)) .bg(bg_color) .hover(|style| style.bg(bg_hover_color)) .active(|style| style.bg(bg_active_color)) diff --git a/crates/ui2/src/components/keybinding.rs b/crates/ui2/src/components/keybinding.rs index 455cfe5b59..88cabbdc88 100644 --- a/crates/ui2/src/components/keybinding.rs +++ b/crates/ui2/src/components/keybinding.rs @@ -60,15 +60,13 @@ impl Key { } fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { - let theme = theme(cx); - div() .px_2() .py_0() .rounded_md() .text_sm() - .text_color(theme.text) - .bg(theme.filled_element) + .text_color(cx.theme().colors().text) + .bg(cx.theme().colors().element) .child(self.key.clone()) } } diff --git a/crates/ui2/src/components/list.rs b/crates/ui2/src/components/list.rs index 9557e68d7f..1668592a38 100644 --- a/crates/ui2/src/components/list.rs +++ b/crates/ui2/src/components/list.rs @@ -89,8 +89,6 @@ impl ListHeader { } fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { - let theme = theme(cx); - let is_toggleable = self.toggleable != Toggleable::NotToggleable; let is_toggled = self.toggleable.is_toggled(); @@ -99,9 +97,10 @@ impl ListHeader { h_stack() .flex_1() .w_full() - .bg(theme.surface) + .bg(cx.theme().colors().surface) .when(self.state == InteractionState::Focused, |this| { - this.border().border_color(theme.border_focused) + this.border() + .border_color(cx.theme().colors().border_focused) }) .relative() .child( @@ -363,7 +362,6 @@ impl ListEntry { fn render(mut self, _view: &mut V, cx: &mut ViewContext) -> impl Component { let settings = user_settings(cx); - let theme = theme(cx); let left_content = match self.left_content.clone() { Some(LeftContent::Icon(i)) => Some( @@ -385,9 +383,10 @@ impl ListEntry { div() .relative() .group("") - .bg(theme.surface) + .bg(cx.theme().colors().surface) .when(self.state == InteractionState::Focused, |this| { - this.border().border_color(theme.border_focused) + this.border() + .border_color(cx.theme().colors().border_focused) }) .child( sized_item @@ -399,11 +398,11 @@ impl ListEntry { .h_full() .flex() .justify_center() - .group_hover("", |style| style.bg(theme.border_focused)) + .group_hover("", |style| style.bg(cx.theme().colors().border_focused)) .child( h_stack() .child(div().w_px().h_full()) - .child(div().w_px().h_full().bg(theme.border)), + .child(div().w_px().h_full().bg(cx.theme().colors().border)), ) })) .flex() @@ -472,19 +471,18 @@ impl ListDetailsEntry { } fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { - let theme = theme(cx); let settings = user_settings(cx); let (item_bg, item_bg_hover, item_bg_active) = match self.seen { true => ( - theme.ghost_element, - theme.ghost_element_hover, - theme.ghost_element_active, + cx.theme().colors().ghost_element, + cx.theme().colors().ghost_element_hover, + cx.theme().colors().ghost_element_active, ), false => ( - theme.filled_element, - theme.filled_element_hover, - theme.filled_element_active, + cx.theme().colors().element, + cx.theme().colors().element_hover, + cx.theme().colors().element_active, ), }; @@ -524,9 +522,7 @@ impl ListSeparator { } fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { - let theme = theme(cx); - - div().h_px().w_full().bg(theme.border) + div().h_px().w_full().bg(cx.theme().colors().border) } } diff --git a/crates/ui2/src/components/modal.rs b/crates/ui2/src/components/modal.rs index 7c3efe79ba..26986474e0 100644 --- a/crates/ui2/src/components/modal.rs +++ b/crates/ui2/src/components/modal.rs @@ -39,22 +39,20 @@ impl Modal { } fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { - let theme = theme(cx); - v_stack() .id(self.id.clone()) .w_96() // .rounded_xl() - .bg(theme.background) + .bg(cx.theme().colors().background) .border() - .border_color(theme.border) + .border_color(cx.theme().colors().border) .shadow_2xl() .child( h_stack() .justify_between() .p_1() .border_b() - .border_color(theme.border) + .border_color(cx.theme().colors().border) .child(div().children(self.title.clone().map(|t| Label::new(t)))) .child(IconButton::new("close", Icon::Close)), ) @@ -65,7 +63,7 @@ impl Modal { this.child( h_stack() .border_t() - .border_color(theme.border) + .border_color(cx.theme().colors().border) .p_1() .justify_end() .children(self.secondary_action) diff --git a/crates/ui2/src/components/multi_buffer.rs b/crates/ui2/src/components/multi_buffer.rs index 696fc77a62..ea130f20bd 100644 --- a/crates/ui2/src/components/multi_buffer.rs +++ b/crates/ui2/src/components/multi_buffer.rs @@ -12,8 +12,6 @@ impl MultiBuffer { } fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { - let theme = theme(cx); - v_stack() .w_full() .h_full() @@ -26,7 +24,7 @@ impl MultiBuffer { .items_center() .justify_between() .p_4() - .bg(theme.editor_subheader) + .bg(cx.theme().colors().editor_subheader) .child(Label::new("main.rs")) .child(IconButton::new("arrow_up_right", Icon::ArrowUpRight)), ) @@ -50,17 +48,15 @@ mod stories { type Element = Div; fn render(&mut self, cx: &mut ViewContext) -> Self::Element { - let theme = theme(cx); - Story::container(cx) .child(Story::title_for::<_, MultiBuffer>(cx)) .child(Story::label(cx, "Default")) .child(MultiBuffer::new(vec![ - hello_world_rust_buffer_example(&theme), - hello_world_rust_buffer_example(&theme), - hello_world_rust_buffer_example(&theme), - hello_world_rust_buffer_example(&theme), - hello_world_rust_buffer_example(&theme), + hello_world_rust_buffer_example(cx), + hello_world_rust_buffer_example(cx), + hello_world_rust_buffer_example(cx), + hello_world_rust_buffer_example(cx), + hello_world_rust_buffer_example(cx), ])) } } diff --git a/crates/ui2/src/components/notification_toast.rs b/crates/ui2/src/components/notification_toast.rs index f7d280ed16..59078c98f4 100644 --- a/crates/ui2/src/components/notification_toast.rs +++ b/crates/ui2/src/components/notification_toast.rs @@ -1,6 +1,7 @@ use gpui2::rems; -use crate::{h_stack, prelude::*, Icon}; +use crate::prelude::*; +use crate::{h_stack, Icon}; #[derive(Component)] pub struct NotificationToast { @@ -22,8 +23,6 @@ impl NotificationToast { } fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { - let theme = theme(cx); - h_stack() .z_index(5) .absolute() @@ -35,7 +34,7 @@ impl NotificationToast { .px_1p5() .rounded_lg() .shadow_md() - .bg(theme.elevated_surface) + .bg(cx.theme().colors().elevated_surface) .child(div().size_full().child(self.label.clone())) } } diff --git a/crates/ui2/src/components/notifications_panel.rs b/crates/ui2/src/components/notifications_panel.rs index 6872f116e9..10b0e07af6 100644 --- a/crates/ui2/src/components/notifications_panel.rs +++ b/crates/ui2/src/components/notifications_panel.rs @@ -12,15 +12,13 @@ impl NotificationsPanel { } fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { - let theme = theme(cx); - div() .id(self.id.clone()) .flex() .flex_col() .w_full() .h_full() - .bg(theme.surface) + .bg(cx.theme().colors().surface) .child( div() .id("header") diff --git a/crates/ui2/src/components/palette.rs b/crates/ui2/src/components/palette.rs index e47f6a4cea..a1f3eb7e1c 100644 --- a/crates/ui2/src/components/palette.rs +++ b/crates/ui2/src/components/palette.rs @@ -43,22 +43,20 @@ impl Palette { } fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { - let theme = theme(cx); - v_stack() .id(self.id.clone()) .w_96() .rounded_lg() - .bg(theme.elevated_surface) + .bg(cx.theme().colors().elevated_surface) .border() - .border_color(theme.border) + .border_color(cx.theme().colors().border) .child( v_stack() .gap_px() .child(v_stack().py_0p5().px_1().child(div().px_2().py_0p5().child( Label::new(self.input_placeholder.clone()).color(LabelColor::Placeholder), ))) - .child(div().h_px().w_full().bg(theme.filled_element)) + .child(div().h_px().w_full().bg(cx.theme().colors().element)) .child( v_stack() .id("items") @@ -88,8 +86,12 @@ impl Palette { .px_2() .py_0p5() .rounded_lg() - .hover(|style| style.bg(theme.ghost_element_hover)) - .active(|style| style.bg(theme.ghost_element_active)) + .hover(|style| { + style.bg(cx.theme().colors().ghost_element_hover) + }) + .active(|style| { + style.bg(cx.theme().colors().ghost_element_active) + }) .child(item) })), ), diff --git a/crates/ui2/src/components/panel.rs b/crates/ui2/src/components/panel.rs index 12d2207ffd..c4a9ac5111 100644 --- a/crates/ui2/src/components/panel.rs +++ b/crates/ui2/src/components/panel.rs @@ -93,8 +93,6 @@ impl Panel { } fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { - let theme = theme(cx); - let current_size = self.width.unwrap_or(self.initial_width); v_stack() @@ -111,8 +109,8 @@ impl Panel { .when(self.current_side == PanelSide::Bottom, |this| { this.border_b().w_full().h(current_size) }) - .bg(theme.surface) - .border_color(theme.border) + .bg(cx.theme().colors().surface) + .border_color(cx.theme().colors().border) .children(self.children) } } diff --git a/crates/ui2/src/components/panes.rs b/crates/ui2/src/components/panes.rs index 854786ebaa..167e837083 100644 --- a/crates/ui2/src/components/panes.rs +++ b/crates/ui2/src/components/panes.rs @@ -90,8 +90,6 @@ impl PaneGroup { } fn render(self, view: &mut V, cx: &mut ViewContext) -> impl Component { - let theme = theme(cx); - if !self.panes.is_empty() { let el = div() .flex() @@ -115,7 +113,7 @@ impl PaneGroup { .gap_px() .w_full() .h_full() - .bg(theme.editor) + .bg(cx.theme().colors().editor) .children(self.groups.into_iter().map(|group| group.render(view, cx))); if self.split_direction == SplitDirection::Horizontal { diff --git a/crates/ui2/src/components/player_stack.rs b/crates/ui2/src/components/player_stack.rs index ced761a086..1a1231e6c4 100644 --- a/crates/ui2/src/components/player_stack.rs +++ b/crates/ui2/src/components/player_stack.rs @@ -14,9 +14,7 @@ impl PlayerStack { } fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { - let theme = theme(cx); let player = self.player_with_call_status.get_player(); - self.player_with_call_status.get_call_status(); let followers = self .player_with_call_status @@ -50,7 +48,7 @@ impl PlayerStack { .pl_1() .rounded_lg() .bg(if followers.is_none() { - theme.transparent + cx.theme().styles.system.transparent } else { player.selection_color(cx) }) diff --git a/crates/ui2/src/components/project_panel.rs b/crates/ui2/src/components/project_panel.rs index 84c68119fe..76fa50d338 100644 --- a/crates/ui2/src/components/project_panel.rs +++ b/crates/ui2/src/components/project_panel.rs @@ -14,15 +14,13 @@ impl ProjectPanel { } fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { - let theme = theme(cx); - div() .id(self.id.clone()) .flex() .flex_col() .w_full() .h_full() - .bg(theme.surface) + .bg(cx.theme().colors().surface) .child( div() .id("project-panel-contents") diff --git a/crates/ui2/src/components/status_bar.rs b/crates/ui2/src/components/status_bar.rs index a23040193f..136472f605 100644 --- a/crates/ui2/src/components/status_bar.rs +++ b/crates/ui2/src/components/status_bar.rs @@ -86,8 +86,6 @@ impl StatusBar { view: &mut Workspace, cx: &mut ViewContext, ) -> impl Component { - let theme = theme(cx); - div() .py_0p5() .px_1() @@ -95,7 +93,7 @@ impl StatusBar { .items_center() .justify_between() .w_full() - .bg(theme.status_bar) + .bg(cx.theme().colors().status_bar) .child(self.left_tools(view, cx)) .child(self.right_tools(view, cx)) } diff --git a/crates/ui2/src/components/tab.rs b/crates/ui2/src/components/tab.rs index d784ec0174..5f20af0955 100644 --- a/crates/ui2/src/components/tab.rs +++ b/crates/ui2/src/components/tab.rs @@ -87,7 +87,6 @@ impl Tab { } fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { - let theme = theme(cx); let has_fs_conflict = self.fs_status == FileSystemStatus::Conflict; let is_deleted = self.fs_status == FileSystemStatus::Deleted; @@ -110,14 +109,14 @@ impl Tab { let (tab_bg, tab_hover_bg, tab_active_bg) = match self.current { true => ( - theme.ghost_element, - theme.ghost_element_hover, - theme.ghost_element_active, + cx.theme().colors().ghost_element, + cx.theme().colors().ghost_element_hover, + cx.theme().colors().ghost_element_active, ), false => ( - theme.filled_element, - theme.filled_element_hover, - theme.filled_element_active, + cx.theme().colors().element, + cx.theme().colors().element_hover, + cx.theme().colors().element_active, ), }; diff --git a/crates/ui2/src/components/tab_bar.rs b/crates/ui2/src/components/tab_bar.rs index da0a41a1bf..550105b98e 100644 --- a/crates/ui2/src/components/tab_bar.rs +++ b/crates/ui2/src/components/tab_bar.rs @@ -24,15 +24,13 @@ impl TabBar { } fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { - let theme = theme(cx); - let (can_navigate_back, can_navigate_forward) = self.can_navigate; div() .id(self.id.clone()) .w_full() .flex() - .bg(theme.tab_bar) + .bg(cx.theme().colors().tab_bar) // Left Side .child( div() diff --git a/crates/ui2/src/components/terminal.rs b/crates/ui2/src/components/terminal.rs index a751d47dfc..051ebf7315 100644 --- a/crates/ui2/src/components/terminal.rs +++ b/crates/ui2/src/components/terminal.rs @@ -12,8 +12,6 @@ impl Terminal { } fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { - let theme = theme(cx); - let can_navigate_back = true; let can_navigate_forward = false; @@ -26,7 +24,7 @@ impl Terminal { div() .w_full() .flex() - .bg(theme.surface) + .bg(cx.theme().colors().surface) .child( div().px_1().flex().flex_none().gap_2().child( div() @@ -73,7 +71,7 @@ impl Terminal { height: rems(36.).into(), }, ) - .child(crate::static_data::terminal_buffer(&theme)), + .child(crate::static_data::terminal_buffer(cx)), ) } } diff --git a/crates/ui2/src/components/title_bar.rs b/crates/ui2/src/components/title_bar.rs index 4b3b125dea..2fa201440a 100644 --- a/crates/ui2/src/components/title_bar.rs +++ b/crates/ui2/src/components/title_bar.rs @@ -89,7 +89,6 @@ impl Render for TitleBar { type Element = Div; fn render(&mut self, cx: &mut ViewContext) -> Div { - let theme = theme(cx); let settings = user_settings(cx); // let has_focus = cx.window_is_active(); @@ -106,7 +105,7 @@ impl Render for TitleBar { .items_center() .justify_between() .w_full() - .bg(theme.background) + .bg(cx.theme().colors().background) .py_1() .child( div() diff --git a/crates/ui2/src/components/toast.rs b/crates/ui2/src/components/toast.rs index 814e91c498..3b81ac42b4 100644 --- a/crates/ui2/src/components/toast.rs +++ b/crates/ui2/src/components/toast.rs @@ -37,8 +37,6 @@ impl Toast { } fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { - let theme = theme(cx); - let mut div = div(); if self.origin == ToastOrigin::Bottom { @@ -56,7 +54,7 @@ impl Toast { .rounded_lg() .shadow_md() .overflow_hidden() - .bg(theme.elevated_surface) + .bg(cx.theme().colors().elevated_surface) .children(self.children) } } diff --git a/crates/ui2/src/components/toolbar.rs b/crates/ui2/src/components/toolbar.rs index 4b35e2d9d2..05a5c991d6 100644 --- a/crates/ui2/src/components/toolbar.rs +++ b/crates/ui2/src/components/toolbar.rs @@ -55,10 +55,8 @@ impl Toolbar { } fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { - let theme = theme(cx); - div() - .bg(theme.toolbar) + .bg(cx.theme().colors().toolbar) .p_2() .flex() .justify_between() @@ -87,8 +85,6 @@ mod stories { 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::label(cx, "Default")) @@ -100,21 +96,21 @@ mod stories { Symbol(vec![ HighlightedText { text: "impl ".to_string(), - color: theme.syntax.color("keyword"), + color: cx.theme().syntax_color("keyword"), }, HighlightedText { text: "ToolbarStory".to_string(), - color: theme.syntax.color("function"), + color: cx.theme().syntax_color("function"), }, ]), Symbol(vec![ HighlightedText { text: "fn ".to_string(), - color: theme.syntax.color("keyword"), + color: cx.theme().syntax_color("keyword"), }, HighlightedText { text: "render".to_string(), - color: theme.syntax.color("function"), + color: cx.theme().syntax_color("function"), }, ]), ], diff --git a/crates/ui2/src/components/traffic_lights.rs b/crates/ui2/src/components/traffic_lights.rs index 8ee19d26f5..9080276cdd 100644 --- a/crates/ui2/src/components/traffic_lights.rs +++ b/crates/ui2/src/components/traffic_lights.rs @@ -22,13 +22,13 @@ impl TrafficLight { } fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { - let theme = theme(cx); + let system_colors = &cx.theme().styles.system; let fill = match (self.window_has_focus, self.color) { - (true, TrafficLightColor::Red) => theme.mac_os_traffic_light_red, - (true, TrafficLightColor::Yellow) => theme.mac_os_traffic_light_yellow, - (true, TrafficLightColor::Green) => theme.mac_os_traffic_light_green, - (false, _) => theme.filled_element, + (true, TrafficLightColor::Red) => system_colors.mac_os_traffic_light_red, + (true, TrafficLightColor::Yellow) => system_colors.mac_os_traffic_light_yellow, + (true, TrafficLightColor::Green) => system_colors.mac_os_traffic_light_green, + (false, _) => cx.theme().colors().element, }; div().w_3().h_3().rounded_full().bg(fill) diff --git a/crates/ui2/src/components/workspace.rs b/crates/ui2/src/components/workspace.rs index 78ab6232a8..97570a33e3 100644 --- a/crates/ui2/src/components/workspace.rs +++ b/crates/ui2/src/components/workspace.rs @@ -1,14 +1,16 @@ use std::sync::Arc; use chrono::DateTime; -use gpui2::{px, relative, rems, Div, Render, Size, View, VisualContext}; +use gpui2::{px, relative, Div, Render, Size, View, VisualContext}; +use settings2::Settings; +use theme2::ThemeSettings; -use crate::{prelude::*, NotificationsPanel}; +use crate::prelude::*; 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, + static_livestream, v_stack, AssistantPanel, Button, ChatMessage, ChatPanel, CollabPanel, + EditorPane, Label, LanguageSelector, NotificationsPanel, Pane, PaneGroup, Panel, + PanelAllowedSides, PanelSide, ProjectPanel, SplitDirection, StatusBar, Terminal, TitleBar, + Toast, ToastOrigin, }; #[derive(Clone)] @@ -150,6 +152,18 @@ impl Workspace { pub fn debug_toggle_user_settings(&mut self, cx: &mut ViewContext) { self.debug.enable_user_settings = !self.debug.enable_user_settings; + let mut theme_settings = ThemeSettings::get_global(cx).clone(); + + if self.debug.enable_user_settings { + theme_settings.ui_font_size = 18.0.into(); + } else { + theme_settings.ui_font_size = 16.0.into(); + } + + ThemeSettings::override_global(theme_settings.clone(), cx); + + cx.set_rem_size(theme_settings.ui_font_size); + cx.notify(); } @@ -179,22 +193,6 @@ 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. - // Need to talk with Nathan/Antonio about this. - { - let settings = user_settings_mut(cx); - - if self.debug.enable_user_settings { - settings.list_indent_depth = SettingValue::UserDefined(rems(0.5).into()); - settings.ui_scale = SettingValue::UserDefined(1.25); - } else { - *settings = FakeSettings::default(); - } - } - let root_group = PaneGroup::new_panes( vec![Pane::new( "pane-0", @@ -216,8 +214,8 @@ impl Render for Workspace { .gap_0() .justify_start() .items_start() - .text_color(theme.text) - .bg(theme.background) + .text_color(cx.theme().colors().text) + .bg(cx.theme().colors().background) .child(self.title_bar.clone()) .child( div() @@ -228,7 +226,7 @@ impl Render for Workspace { .overflow_hidden() .border_t() .border_b() - .border_color(theme.border) + .border_color(cx.theme().colors().border) .children( Some( Panel::new("project-panel-outer", cx) @@ -323,7 +321,7 @@ impl Render for Workspace { v_stack() .z_index(9) .absolute() - .bottom_10() + .top_20() .left_1_4() .w_40() .gap_2() diff --git a/crates/ui2/src/elements/avatar.rs b/crates/ui2/src/elements/avatar.rs index f008eeb479..ff92021b11 100644 --- a/crates/ui2/src/elements/avatar.rs +++ b/crates/ui2/src/elements/avatar.rs @@ -22,8 +22,6 @@ impl Avatar { } fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { - let theme = theme(cx); - let mut img = img(); if self.shape == Shape::Circle { @@ -34,7 +32,8 @@ impl Avatar { img.uri(self.src.clone()) .size_4() - .bg(theme.image_fallback_background) + // todo!(Pull the avatar fallback background from the theme.) + .bg(gpui2::red()) } } diff --git a/crates/ui2/src/elements/button.rs b/crates/ui2/src/elements/button.rs index d27a0537d8..073bcdbb45 100644 --- a/crates/ui2/src/elements/button.rs +++ b/crates/ui2/src/elements/button.rs @@ -1,9 +1,9 @@ use std::sync::Arc; -use gpui2::{div, DefiniteLength, Hsla, MouseButton, WindowContext}; +use gpui2::{div, rems, DefiniteLength, Hsla, MouseButton, WindowContext}; -use crate::{h_stack, Icon, IconColor, IconElement, Label, LabelColor}; -use crate::{prelude::*, LineHeightStyle}; +use crate::prelude::*; +use crate::{h_stack, Icon, IconColor, IconElement, Label, LabelColor, LineHeightStyle}; #[derive(Default, PartialEq, Clone, Copy)] pub enum IconPosition { @@ -21,29 +21,23 @@ pub enum ButtonVariant { impl ButtonVariant { pub fn bg_color(&self, cx: &mut WindowContext) -> Hsla { - let theme = theme(cx); - match self { - ButtonVariant::Ghost => theme.ghost_element, - ButtonVariant::Filled => theme.filled_element, + ButtonVariant::Ghost => cx.theme().colors().ghost_element, + ButtonVariant::Filled => cx.theme().colors().element, } } pub fn bg_color_hover(&self, cx: &mut WindowContext) -> Hsla { - let theme = theme(cx); - match self { - ButtonVariant::Ghost => theme.ghost_element_hover, - ButtonVariant::Filled => theme.filled_element_hover, + ButtonVariant::Ghost => cx.theme().colors().ghost_element_hover, + ButtonVariant::Filled => cx.theme().colors().element_hover, } } pub fn bg_color_active(&self, cx: &mut WindowContext) -> Hsla { - let theme = theme(cx); - match self { - ButtonVariant::Ghost => theme.ghost_element_active, - ButtonVariant::Filled => theme.filled_element_active, + ButtonVariant::Ghost => cx.theme().colors().ghost_element_active, + ButtonVariant::Filled => cx.theme().colors().element_active, } } } @@ -157,7 +151,7 @@ impl Button { .relative() .id(SharedString::from(format!("{}", self.label))) .p_1() - .text_size(ui_size(cx, 1.)) + .text_size(rems(1.)) .rounded_md() .bg(self.variant.bg_color(cx)) .hover(|style| style.bg(self.variant.bg_color_hover(cx))) @@ -204,7 +198,7 @@ impl ButtonGroup { } fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { - let mut el = h_stack().text_size(ui_size(cx, 1.)); + let mut el = h_stack().text_size(rems(1.)); for button in self.buttons { el = el.child(button.render(_view, cx)); diff --git a/crates/ui2/src/elements/details.rs b/crates/ui2/src/elements/details.rs index eca7798c82..1d22c81774 100644 --- a/crates/ui2/src/elements/details.rs +++ b/crates/ui2/src/elements/details.rs @@ -1,4 +1,5 @@ -use crate::{prelude::*, v_stack, ButtonGroup}; +use crate::prelude::*; +use crate::{v_stack, ButtonGroup}; #[derive(Component)] pub struct Details { @@ -27,13 +28,11 @@ impl Details { } fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { - let theme = theme(cx); - v_stack() .p_1() .gap_0p5() .text_xs() - .text_color(theme.text) + .text_color(cx.theme().colors().text) .size_full() .child(self.text) .children(self.meta.map(|m| m)) diff --git a/crates/ui2/src/elements/icon.rs b/crates/ui2/src/elements/icon.rs index 4e4ec2bce7..8cc62f4a8d 100644 --- a/crates/ui2/src/elements/icon.rs +++ b/crates/ui2/src/elements/icon.rs @@ -1,4 +1,4 @@ -use gpui2::{svg, Hsla}; +use gpui2::{rems, svg, Hsla}; use strum::EnumIter; use crate::prelude::*; @@ -26,13 +26,14 @@ pub enum IconColor { impl IconColor { pub fn color(self, cx: &WindowContext) -> Hsla { - let theme = theme(cx); + let theme_colors = cx.theme().colors(); + match self { - IconColor::Default => gpui2::red(), - IconColor::Muted => gpui2::red(), - IconColor::Disabled => gpui2::red(), - IconColor::Placeholder => gpui2::red(), - IconColor::Accent => gpui2::red(), + IconColor::Default => theme_colors.icon, + IconColor::Muted => theme_colors.icon_muted, + IconColor::Disabled => theme_colors.icon_disabled, + IconColor::Placeholder => theme_colors.icon_placeholder, + IconColor::Accent => theme_colors.icon_accent, IconColor::Error => gpui2::red(), IconColor::Warning => gpui2::red(), IconColor::Success => gpui2::red(), @@ -174,8 +175,8 @@ impl IconElement { fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { let fill = self.color.color(cx); let svg_size = match self.size { - IconSize::Small => ui_size(cx, 12. / 14.), - IconSize::Medium => ui_size(cx, 15. / 14.), + IconSize::Small => rems(0.75), + IconSize::Medium => rems(0.9375), }; svg() diff --git a/crates/ui2/src/elements/input.rs b/crates/ui2/src/elements/input.rs index e9e92dd0a6..3f82512b84 100644 --- a/crates/ui2/src/elements/input.rs +++ b/crates/ui2/src/elements/input.rs @@ -57,18 +57,16 @@ impl Input { } fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { - let theme = theme(cx); - let (input_bg, input_hover_bg, input_active_bg) = match self.variant { InputVariant::Ghost => ( - theme.ghost_element, - theme.ghost_element_hover, - theme.ghost_element_active, + cx.theme().colors().ghost_element, + cx.theme().colors().ghost_element_hover, + cx.theme().colors().ghost_element_active, ), InputVariant::Filled => ( - theme.filled_element, - theme.filled_element_hover, - theme.filled_element_active, + cx.theme().colors().element, + cx.theme().colors().element_hover, + cx.theme().colors().element_active, ), }; @@ -90,7 +88,7 @@ impl Input { .w_full() .px_2() .border() - .border_color(theme.transparent) + .border_color(cx.theme().styles.system.transparent) .bg(input_bg) .hover(|style| style.bg(input_hover_bg)) .active(|style| style.bg(input_active_bg)) diff --git a/crates/ui2/src/elements/label.rs b/crates/ui2/src/elements/label.rs index 4d336345fb..dcc28a3319 100644 --- a/crates/ui2/src/elements/label.rs +++ b/crates/ui2/src/elements/label.rs @@ -1,4 +1,4 @@ -use gpui2::{relative, Hsla, WindowContext}; +use gpui2::{relative, rems, Hsla, WindowContext}; use smallvec::SmallVec; use crate::prelude::*; @@ -18,18 +18,16 @@ pub enum LabelColor { impl LabelColor { pub fn hsla(&self, cx: &WindowContext) -> Hsla { - let theme = theme(cx); - match self { - Self::Default => theme.text, - Self::Muted => theme.text_muted, + Self::Default => cx.theme().colors().text, + Self::Muted => cx.theme().colors().text_muted, Self::Created => gpui2::red(), Self::Modified => gpui2::red(), Self::Deleted => gpui2::red(), - Self::Disabled => theme.text_disabled, + Self::Disabled => cx.theme().colors().text_disabled, Self::Hidden => gpui2::red(), - Self::Placeholder => theme.text_placeholder, - Self::Accent => gpui2::red(), + Self::Placeholder => cx.theme().colors().text_placeholder, + Self::Accent => cx.theme().colors().text_accent, } } } @@ -88,7 +86,7 @@ impl Label { .bg(LabelColor::Hidden.hsla(cx)), ) }) - .text_size(ui_size(cx, 1.)) + .text_size(rems(1.)) .when(self.line_height_style == LineHeightStyle::UILabel, |this| { this.line_height(relative(1.)) }) @@ -126,9 +124,7 @@ impl HighlightedLabel { } fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { - let theme = theme(cx); - - let highlight_color = theme.text_accent; + let highlight_color = cx.theme().colors().text_accent; let mut highlight_indices = self.highlight_indices.iter().copied().peekable(); diff --git a/crates/ui2/src/elements/player.rs b/crates/ui2/src/elements/player.rs index 5bf890b8bb..8e3ad5c3a8 100644 --- a/crates/ui2/src/elements/player.rs +++ b/crates/ui2/src/elements/player.rs @@ -1,6 +1,6 @@ use gpui2::{Hsla, ViewContext}; -use crate::theme; +use crate::prelude::*; #[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)] pub enum PlayerStatus { @@ -139,13 +139,11 @@ impl Player { } pub fn cursor_color(&self, cx: &mut ViewContext) -> Hsla { - let theme = theme(cx); - theme.players[self.index].cursor + cx.theme().styles.player.0[self.index].cursor } pub fn selection_color(&self, cx: &mut ViewContext) -> Hsla { - let theme = theme(cx); - theme.players[self.index].selection + cx.theme().styles.player.0[self.index].selection } pub fn avatar_src(&self) -> &str { diff --git a/crates/ui2/src/elements/tool_divider.rs b/crates/ui2/src/elements/tool_divider.rs index e1ebb294a0..8a9bbad97f 100644 --- a/crates/ui2/src/elements/tool_divider.rs +++ b/crates/ui2/src/elements/tool_divider.rs @@ -9,8 +9,6 @@ impl ToolDivider { } fn render(self, _view: &mut V, cx: &mut ViewContext) -> impl Component { - let theme = theme(cx); - - div().w_px().h_3().bg(theme.border) + div().w_px().h_3().bg(cx.theme().colors().border) } } diff --git a/crates/ui2/src/prelude.rs b/crates/ui2/src/prelude.rs index 63405fc2cb..c3f530d70c 100644 --- a/crates/ui2/src/prelude.rs +++ b/crates/ui2/src/prelude.rs @@ -4,21 +4,12 @@ pub use gpui2::{ }; pub use crate::elevation::*; -use crate::settings::user_settings; pub use crate::ButtonVariant; -pub use theme2::theme; +pub use theme2::ActiveTheme; -use gpui2::{rems, Hsla, Rems}; +use gpui2::Hsla; use strum::EnumIter; -pub fn ui_size(cx: &mut WindowContext, size: f32) -> Rems { - const UI_SCALE_RATIO: f32 = 0.875; - - let settings = user_settings(cx); - - rems(*settings.ui_scale * UI_SCALE_RATIO * size) -} - #[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, EnumIter)] pub enum FileSystemStatus { #[default] @@ -54,15 +45,13 @@ pub enum GitStatus { impl GitStatus { pub fn hsla(&self, cx: &WindowContext) -> Hsla { - let theme = theme(cx); - match self { - Self::None => theme.transparent, - Self::Created => theme.git_created, - Self::Modified => theme.git_modified, - Self::Deleted => theme.git_deleted, - Self::Conflict => theme.git_conflict, - Self::Renamed => theme.git_renamed, + Self::None => cx.theme().styles.system.transparent, + Self::Created => cx.theme().styles.git.created, + Self::Modified => cx.theme().styles.git.modified, + Self::Deleted => cx.theme().styles.git.deleted, + Self::Conflict => cx.theme().styles.git.conflict, + Self::Renamed => cx.theme().styles.git.renamed, } } } diff --git a/crates/ui2/src/settings.rs b/crates/ui2/src/settings.rs index 48a2e8e7b4..6a9426f623 100644 --- a/crates/ui2/src/settings.rs +++ b/crates/ui2/src/settings.rs @@ -58,7 +58,6 @@ pub struct FakeSettings { pub list_disclosure_style: SettingValue, pub list_indent_depth: SettingValue, pub titlebar: TitlebarSettings, - pub ui_scale: SettingValue, } impl Default for FakeSettings { @@ -68,7 +67,6 @@ impl Default for FakeSettings { list_disclosure_style: SettingValue::Default(DisclosureControlStyle::ChevronOnHover), list_indent_depth: SettingValue::Default(rems(0.3).into()), default_panel_size: SettingValue::Default(rems(16.).into()), - ui_scale: SettingValue::Default(1.), } } } diff --git a/crates/ui2/src/static_data.rs b/crates/ui2/src/static_data.rs index 68f1e36b2c..7062c81954 100644 --- a/crates/ui2/src/static_data.rs +++ b/crates/ui2/src/static_data.rs @@ -1,12 +1,12 @@ use std::path::PathBuf; use std::str::FromStr; -use gpui2::ViewContext; +use gpui2::{AppContext, ViewContext}; use rand::Rng; -use theme2::Theme; +use theme2::ActiveTheme; use crate::{ - theme, Buffer, BufferRow, BufferRows, Button, EditorPane, FileSystemStatus, GitStatus, + Buffer, BufferRow, BufferRows, Button, EditorPane, FileSystemStatus, GitStatus, HighlightedLine, Icon, Keybinding, Label, LabelColor, ListEntry, ListEntrySize, ListItem, Livestream, MicStatus, ModifierKeys, PaletteItem, Player, PlayerCallStatus, PlayerWithCallStatus, ScreenShareStatus, Symbol, Tab, ToggleState, VideoStatus, @@ -643,8 +643,6 @@ pub fn empty_buffer_example() -> Buffer { } pub fn hello_world_rust_editor_example(cx: &mut ViewContext) -> EditorPane { - let theme = theme(cx); - EditorPane::new( cx, static_tabs_example(), @@ -652,29 +650,29 @@ pub fn hello_world_rust_editor_example(cx: &mut ViewContext) -> Edit vec![Symbol(vec![ HighlightedText { text: "fn ".to_string(), - color: theme.syntax.color("keyword"), + color: cx.theme().syntax_color("keyword"), }, HighlightedText { text: "main".to_string(), - color: theme.syntax.color("function"), + color: cx.theme().syntax_color("function"), }, ])], - hello_world_rust_buffer_example(&theme), + hello_world_rust_buffer_example(cx), ) } -pub fn hello_world_rust_buffer_example(theme: &Theme) -> Buffer { +pub fn hello_world_rust_buffer_example(cx: &AppContext) -> Buffer { Buffer::new("hello-world-rust-buffer") .set_title("hello_world.rs".to_string()) .set_path("src/hello_world.rs".to_string()) .set_language("rust".to_string()) .set_rows(Some(BufferRows { show_line_numbers: true, - rows: hello_world_rust_buffer_rows(theme), + rows: hello_world_rust_buffer_rows(cx), })) } -pub fn hello_world_rust_buffer_rows(theme: &Theme) -> Vec { +pub fn hello_world_rust_buffer_rows(cx: &AppContext) -> Vec { let show_line_number = true; vec![ @@ -686,15 +684,15 @@ pub fn hello_world_rust_buffer_rows(theme: &Theme) -> Vec { highlighted_texts: vec![ HighlightedText { text: "fn ".to_string(), - color: theme.syntax.color("keyword"), + color: cx.theme().syntax_color("keyword"), }, HighlightedText { text: "main".to_string(), - color: theme.syntax.color("function"), + color: cx.theme().syntax_color("function"), }, HighlightedText { text: "() {".to_string(), - color: theme.text, + color: cx.theme().colors().text, }, ], }), @@ -710,7 +708,7 @@ pub fn hello_world_rust_buffer_rows(theme: &Theme) -> Vec { highlighted_texts: vec![HighlightedText { text: " // Statements here are executed when the compiled binary is called." .to_string(), - color: theme.syntax.color("comment"), + color: cx.theme().syntax_color("comment"), }], }), cursors: None, @@ -733,7 +731,7 @@ pub fn hello_world_rust_buffer_rows(theme: &Theme) -> Vec { line: Some(HighlightedLine { highlighted_texts: vec![HighlightedText { text: " // Print text to the console.".to_string(), - color: theme.syntax.color("comment"), + color: cx.theme().syntax_color("comment"), }], }), cursors: None, @@ -748,15 +746,15 @@ pub fn hello_world_rust_buffer_rows(theme: &Theme) -> Vec { highlighted_texts: vec![ HighlightedText { text: " println!(".to_string(), - color: theme.text, + color: cx.theme().colors().text, }, HighlightedText { text: "\"Hello, world!\"".to_string(), - color: theme.syntax.color("string"), + color: cx.theme().syntax_color("string"), }, HighlightedText { text: ");".to_string(), - color: theme.text, + color: cx.theme().colors().text, }, ], }), @@ -771,7 +769,7 @@ pub fn hello_world_rust_buffer_rows(theme: &Theme) -> Vec { line: Some(HighlightedLine { highlighted_texts: vec![HighlightedText { text: "}".to_string(), - color: theme.text, + color: cx.theme().colors().text, }], }), cursors: None, @@ -782,8 +780,6 @@ pub fn hello_world_rust_buffer_rows(theme: &Theme) -> Vec { } pub fn hello_world_rust_editor_with_status_example(cx: &mut ViewContext) -> EditorPane { - let theme = theme(cx); - EditorPane::new( cx, static_tabs_example(), @@ -791,29 +787,29 @@ pub fn hello_world_rust_editor_with_status_example(cx: &mut ViewContext Buffer { +pub fn hello_world_rust_buffer_with_status_example(cx: &AppContext) -> Buffer { Buffer::new("hello-world-rust-buffer-with-status") .set_title("hello_world.rs".to_string()) .set_path("src/hello_world.rs".to_string()) .set_language("rust".to_string()) .set_rows(Some(BufferRows { show_line_numbers: true, - rows: hello_world_rust_with_status_buffer_rows(theme), + rows: hello_world_rust_with_status_buffer_rows(cx), })) } -pub fn hello_world_rust_with_status_buffer_rows(theme: &Theme) -> Vec { +pub fn hello_world_rust_with_status_buffer_rows(cx: &AppContext) -> Vec { let show_line_number = true; vec![ @@ -825,15 +821,15 @@ pub fn hello_world_rust_with_status_buffer_rows(theme: &Theme) -> Vec highlighted_texts: vec![ HighlightedText { text: "fn ".to_string(), - color: theme.syntax.color("keyword"), + color: cx.theme().syntax_color("keyword"), }, HighlightedText { text: "main".to_string(), - color: theme.syntax.color("function"), + color: cx.theme().syntax_color("function"), }, HighlightedText { text: "() {".to_string(), - color: theme.text, + color: cx.theme().colors().text, }, ], }), @@ -849,7 +845,7 @@ pub fn hello_world_rust_with_status_buffer_rows(theme: &Theme) -> Vec highlighted_texts: vec![HighlightedText { text: "// Statements here are executed when the compiled binary is called." .to_string(), - color: theme.syntax.color("comment"), + color: cx.theme().syntax_color("comment"), }], }), cursors: None, @@ -872,7 +868,7 @@ pub fn hello_world_rust_with_status_buffer_rows(theme: &Theme) -> Vec line: Some(HighlightedLine { highlighted_texts: vec![HighlightedText { text: " // Print text to the console.".to_string(), - color: theme.syntax.color("comment"), + color: cx.theme().syntax_color("comment"), }], }), cursors: None, @@ -887,15 +883,15 @@ pub fn hello_world_rust_with_status_buffer_rows(theme: &Theme) -> Vec highlighted_texts: vec![ HighlightedText { text: " println!(".to_string(), - color: theme.text, + color: cx.theme().colors().text, }, HighlightedText { text: "\"Hello, world!\"".to_string(), - color: theme.syntax.color("string"), + color: cx.theme().syntax_color("string"), }, HighlightedText { text: ");".to_string(), - color: theme.text, + color: cx.theme().colors().text, }, ], }), @@ -910,7 +906,7 @@ pub fn hello_world_rust_with_status_buffer_rows(theme: &Theme) -> Vec line: Some(HighlightedLine { highlighted_texts: vec![HighlightedText { text: "}".to_string(), - color: theme.text, + color: cx.theme().colors().text, }], }), cursors: None, @@ -924,7 +920,7 @@ pub fn hello_world_rust_with_status_buffer_rows(theme: &Theme) -> Vec line: Some(HighlightedLine { highlighted_texts: vec![HighlightedText { text: "".to_string(), - color: theme.text, + color: cx.theme().colors().text, }], }), cursors: None, @@ -938,7 +934,7 @@ pub fn hello_world_rust_with_status_buffer_rows(theme: &Theme) -> Vec line: Some(HighlightedLine { highlighted_texts: vec![HighlightedText { text: "// Marshall and Nate were here".to_string(), - color: theme.syntax.color("comment"), + color: cx.theme().syntax_color("comment"), }], }), cursors: None, @@ -948,16 +944,16 @@ pub fn hello_world_rust_with_status_buffer_rows(theme: &Theme) -> Vec ] } -pub fn terminal_buffer(theme: &Theme) -> Buffer { +pub fn terminal_buffer(cx: &AppContext) -> Buffer { Buffer::new("terminal") .set_title("zed — fish".to_string()) .set_rows(Some(BufferRows { show_line_numbers: false, - rows: terminal_buffer_rows(theme), + rows: terminal_buffer_rows(cx), })) } -pub fn terminal_buffer_rows(theme: &Theme) -> Vec { +pub fn terminal_buffer_rows(cx: &AppContext) -> Vec { let show_line_number = false; vec![ @@ -969,31 +965,31 @@ pub fn terminal_buffer_rows(theme: &Theme) -> Vec { highlighted_texts: vec![ HighlightedText { text: "maxdeviant ".to_string(), - color: theme.syntax.color("keyword"), + color: cx.theme().syntax_color("keyword"), }, HighlightedText { text: "in ".to_string(), - color: theme.text, + color: cx.theme().colors().text, }, HighlightedText { text: "profaned-capital ".to_string(), - color: theme.syntax.color("function"), + color: cx.theme().syntax_color("function"), }, HighlightedText { text: "in ".to_string(), - color: theme.text, + color: cx.theme().colors().text, }, HighlightedText { text: "~/p/zed ".to_string(), - color: theme.syntax.color("function"), + color: cx.theme().syntax_color("function"), }, HighlightedText { text: "on ".to_string(), - color: theme.text, + color: cx.theme().colors().text, }, HighlightedText { text: " gpui2-ui ".to_string(), - color: theme.syntax.color("keyword"), + color: cx.theme().syntax_color("keyword"), }, ], }), @@ -1008,7 +1004,7 @@ pub fn terminal_buffer_rows(theme: &Theme) -> Vec { line: Some(HighlightedLine { highlighted_texts: vec![HighlightedText { text: "λ ".to_string(), - color: theme.syntax.color("string"), + color: cx.theme().syntax_color("string"), }], }), cursors: None, diff --git a/crates/ui2/src/story.rs b/crates/ui2/src/story.rs index d2813bd174..dea4e342b4 100644 --- a/crates/ui2/src/story.rs +++ b/crates/ui2/src/story.rs @@ -6,8 +6,6 @@ pub struct Story {} impl Story { pub fn container(cx: &mut ViewContext) -> Div { - let theme = theme(cx); - div() .size_full() .flex() @@ -15,15 +13,13 @@ impl Story { .pt_2() .px_4() .font("Zed Mono") - .bg(theme.background) + .bg(cx.theme().colors().background) } pub fn title(cx: &mut ViewContext, title: &str) -> impl Component { - let theme = theme(cx); - div() .text_xl() - .text_color(theme.text) + .text_color(cx.theme().colors().text) .child(title.to_owned()) } @@ -32,13 +28,11 @@ impl Story { } pub fn label(cx: &mut ViewContext, label: &str) -> impl Component { - let theme = theme(cx); - div() .mt_4() .mb_2() .text_xs() - .text_color(theme.text) + .text_color(cx.theme().colors().text) .child(label.to_owned()) } } diff --git a/crates/zed/Cargo.toml b/crates/zed/Cargo.toml index 250a1814aa..c9012a3a14 100644 --- a/crates/zed/Cargo.toml +++ b/crates/zed/Cargo.toml @@ -3,7 +3,7 @@ authors = ["Nathan Sobo "] description = "The fast, collaborative code editor." edition = "2021" name = "zed" -version = "0.111.0" +version = "0.112.0" publish = false [lib]