Detailed changes
@@ -576,8 +576,9 @@ dependencies = [
[[package]]
name = "async-task"
-version = "4.0.3"
-source = "git+https://github.com/zed-industries/async-task?rev=341b57d6de98cdfd7b418567b8de2022ca993a6e#341b57d6de98cdfd7b418567b8de2022ca993a6e"
+version = "4.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fbb36e985947064623dbd357f727af08ffd077f93d696782f3c56365fa2e2799"
[[package]]
name = "async-tls"
@@ -1440,7 +1441,7 @@ dependencies = [
[[package]]
name = "collab"
-version = "0.33.0"
+version = "0.34.0"
dependencies = [
"anyhow",
"async-trait",
@@ -1925,11 +1926,12 @@ dependencies = [
[[package]]
name = "ctor"
-version = "0.1.20"
-source = "git+https://github.com/zed-industries/rust-ctor?rev=7f824cf6a7943885a649b579f33f9ac53f0d1db6#7f824cf6a7943885a649b579f33f9ac53f0d1db6"
+version = "0.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "30d2b3721e861707777e3195b0158f950ae6dc4a27e4d02ff9f67e3eb3de199e"
dependencies = [
"quote",
- "syn 1.0.109",
+ "syn 2.0.37",
]
[[package]]
@@ -2486,7 +2488,6 @@ dependencies = [
"postage",
"project",
"regex",
- "search",
"serde",
"serde_derive",
"settings",
@@ -3065,7 +3066,6 @@ dependencies = [
"slotmap",
"smallvec",
"smol",
- "sqlez",
"sum_tree",
"taffy",
"thiserror",
@@ -6846,7 +6846,6 @@ dependencies = [
"serde_json",
"serde_json_lenient",
"smallvec",
- "sqlez",
"toml 0.5.11",
"tree-sitter",
"tree-sitter-json 0.19.0",
@@ -7762,6 +7761,7 @@ dependencies = [
"procinfo",
"project",
"rand 0.8.5",
+ "search",
"serde",
"serde_derive",
"settings",
@@ -7837,6 +7837,7 @@ dependencies = [
"convert_case 0.6.0",
"gpui",
"indexmap 1.9.3",
+ "indoc",
"json_comments",
"log",
"palette",
@@ -8488,7 +8489,7 @@ dependencies = [
[[package]]
name = "tree-sitter-nu"
version = "0.0.1"
-source = "git+https://github.com/nushell/tree-sitter-nu?rev=a0b80b2e21e5e39571252dc799e19eb89f1fc912#a0b80b2e21e5e39571252dc799e19eb89f1fc912"
+source = "git+https://github.com/nushell/tree-sitter-nu?rev=26bbaecda0039df4067861ab38ea8ea169f7f5aa#26bbaecda0039df4067861ab38ea8ea169f7f5aa"
dependencies = [
"cc",
"tree-sitter",
@@ -9438,6 +9439,7 @@ dependencies = [
"serde_json",
"settings",
"smallvec",
+ "sqlez",
"terminal",
"theme",
"ui",
@@ -92,10 +92,7 @@ resolver = "2"
anyhow = { version = "1.0.57" }
async-trait = { version = "0.1" }
async-compression = { version = "0.4", features = ["gzip", "futures-io"] }
-# TODO: Switch back to the published version of `ctor` once:
-# 1. A new version of `ctor` is published with this change: https://github.com/mmastrac/rust-ctor/pull/295
-# 2. We've confirmed it's fine to update to the latest version of `ctor` (we're currently on v0.1.20).
-ctor = { git = "https://github.com/zed-industries/rust-ctor", rev = "7f824cf6a7943885a649b579f33f9ac53f0d1db6" }
+ctor = "0.2.6"
derive_more = { version = "0.99.17" }
env_logger = { version = "0.9" }
futures = { version = "0.3" }
@@ -158,13 +155,12 @@ tree-sitter-racket = { git = "https://github.com/zed-industries/tree-sitter-rack
tree-sitter-yaml = { git = "https://github.com/zed-industries/tree-sitter-yaml", rev = "f545a41f57502e1b5ddf2a6668896c1b0620f930"}
tree-sitter-lua = "0.0.14"
tree-sitter-nix = { git = "https://github.com/nix-community/tree-sitter-nix", rev = "66e3e9ce9180ae08fc57372061006ef83f0abde7" }
-tree-sitter-nu = { git = "https://github.com/nushell/tree-sitter-nu", rev = "a0b80b2e21e5e39571252dc799e19eb89f1fc912"}
+tree-sitter-nu = { git = "https://github.com/nushell/tree-sitter-nu", rev = "26bbaecda0039df4067861ab38ea8ea169f7f5aa"}
tree-sitter-vue = {git = "https://github.com/zed-industries/tree-sitter-vue", rev = "6608d9d60c386f19d80af7d8132322fa11199c42"}
tree-sitter-uiua = {git = "https://github.com/shnarazk/tree-sitter-uiua", rev = "9260f11be5900beda4ee6d1a24ab8ddfaf5a19b2"}
[patch.crates-io]
tree-sitter = { git = "https://github.com/tree-sitter/tree-sitter", rev = "31c40449749c4263a91a43593831b82229049a4c" }
-async-task = { git = "https://github.com/zed-industries/async-task", rev = "341b57d6de98cdfd7b418567b8de2022ca993a6e" }
# wasmtime = { git = "https://github.com/bytecodealliance/wasmtime", rev = "v16.0.0" }
# TODO - Remove when a version is released with this PR: https://github.com/servo/core-foundation-rs/pull/457
@@ -402,7 +402,7 @@
"cmd-r": "workspace::ToggleRightDock",
"cmd-j": "workspace::ToggleBottomDock",
"alt-cmd-y": "workspace::CloseAllDocks",
- "cmd-shift-f": "workspace::NewSearch",
+ "cmd-shift-f": "workspace::DeploySearch",
"cmd-k cmd-t": "theme_selector::Toggle",
"cmd-k cmd-s": "zed::OpenKeymap",
"cmd-t": "project_symbols::Toggle",
@@ -38,7 +38,7 @@ use gpui::{
};
use language::{language_settings::SoftWrap, Buffer, LanguageRegistry, ToOffset as _};
use project::Project;
-use search::BufferSearchBar;
+use search::{buffer_search::DivRegistrar, BufferSearchBar};
use semantic_index::{SemanticIndex, SemanticIndexStatus};
use settings::{Settings, SettingsStore};
use std::{
@@ -1156,7 +1156,18 @@ impl Render for AssistantPanel {
div()
});
+ let contents = if self.active_editor().is_some() {
+ let mut registrar = DivRegistrar::new(
+ |panel, cx| panel.toolbar.read(cx).item_of_type::<BufferSearchBar>(),
+ cx,
+ );
+ BufferSearchBar::register_inner(&mut registrar);
+ registrar.into_div()
+ } else {
+ div()
+ };
v_stack()
+ .key_context("AssistantPanel")
.size_full()
.on_action(cx.listener(|this, _: &workspace::NewFile, cx| {
this.new_conversation(cx);
@@ -1175,7 +1186,7 @@ impl Render for AssistantPanel {
Some(self.toolbar.clone())
})
.child(
- div()
+ contents
.flex_1()
.child(if let Some(editor) = self.active_editor() {
editor.clone().into_any_element()
@@ -1275,8 +1286,8 @@ impl Panel for AssistantPanel {
}
}
- fn icon(&self, _cx: &WindowContext) -> Option<Icon> {
- Some(Icon::Ai)
+ fn icon(&self, cx: &WindowContext) -> Option<Icon> {
+ Some(Icon::Ai).filter(|_| AssistantSettings::get_global(cx).button)
}
fn icon_tooltip(&self, _cx: &WindowContext) -> Option<&'static str> {
@@ -2816,8 +2827,8 @@ impl InlineAssistant {
fn handle_codegen_changed(&mut self, _: Model<Codegen>, cx: &mut ViewContext<Self>) {
let is_read_only = !self.codegen.read(cx).idle();
- self.prompt_editor.update(cx, |editor, _cx| {
- let was_read_only = editor.read_only();
+ self.prompt_editor.update(cx, |editor, cx| {
+ let was_read_only = editor.read_only(cx);
if was_read_only != is_read_only {
if is_read_only {
editor.set_read_only(true);
@@ -3052,7 +3063,7 @@ impl InlineAssistant {
fn render_prompt_editor(&self, cx: &mut ViewContext<Self>) -> impl IntoElement {
let settings = ThemeSettings::get_global(cx);
let text_style = TextStyle {
- color: if self.prompt_editor.read(cx).read_only() {
+ color: if self.prompt_editor.read(cx).read_only(cx) {
cx.theme().colors().text_disabled
} else {
cx.theme().colors().text
@@ -270,7 +270,7 @@ impl AutoUpdater {
ReleaseChannel::Nightly => cx
.try_read_global::<AppCommitSha, _>(|sha, _| release.version != sha.0)
.unwrap_or(true),
- _ => release.version.parse::<SemanticVersion>()? <= current_version,
+ _ => release.version.parse::<SemanticVersion>()? > current_version,
};
if !should_download {
@@ -36,12 +36,14 @@ impl ParticipantLocation {
pub struct LocalParticipant {
pub projects: Vec<proto::ParticipantProject>,
pub active_project: Option<WeakModel<Project>>,
+ pub role: proto::ChannelRole,
}
#[derive(Clone, Debug)]
pub struct RemoteParticipant {
pub user: Arc<User>,
pub peer_id: proto::PeerId,
+ pub role: proto::ChannelRole,
pub projects: Vec<proto::ParticipantProject>,
pub location: ParticipantLocation,
pub participant_index: ParticipantIndex,
@@ -247,14 +247,18 @@ impl Room {
let response = client.request(proto::CreateRoom {}).await?;
let room_proto = response.room.ok_or_else(|| anyhow!("invalid room"))?;
let room = cx.new_model(|cx| {
- Self::new(
+ let mut room = Self::new(
room_proto.id,
None,
response.live_kit_connection_info,
client,
user_store,
cx,
- )
+ );
+ if let Some(participant) = room_proto.participants.first() {
+ room.local_participant.role = participant.role()
+ }
+ room
})?;
let initial_project_id = if let Some(initial_project) = initial_project {
@@ -606,6 +610,16 @@ impl Room {
.find(|p| p.peer_id == peer_id)
}
+ pub fn role_for_user(&self, user_id: u64) -> Option<proto::ChannelRole> {
+ self.remote_participants
+ .get(&user_id)
+ .map(|participant| participant.role)
+ }
+
+ pub fn local_participant_is_admin(&self) -> bool {
+ self.local_participant.role == proto::ChannelRole::Admin
+ }
+
pub fn pending_participants(&self) -> &[Arc<User>] {
&self.pending_participants
}
@@ -710,7 +724,20 @@ impl Room {
this.participant_user_ids.clear();
if let Some(participant) = local_participant {
+ let role = participant.role();
this.local_participant.projects = participant.projects;
+ if this.local_participant.role != role {
+ this.local_participant.role = role;
+
+ this.joined_projects.retain(|project| {
+ if let Some(project) = project.upgrade() {
+ project.update(cx, |project, _| project.set_role(role));
+ true
+ } else {
+ false
+ }
+ });
+ }
} else {
this.local_participant.projects.clear();
}
@@ -766,6 +793,7 @@ impl Room {
});
}
+ let role = participant.role();
let location = ParticipantLocation::from_proto(participant.location)
.unwrap_or(ParticipantLocation::External);
if let Some(remote_participant) =
@@ -774,8 +802,11 @@ impl Room {
remote_participant.peer_id = peer_id;
remote_participant.projects = participant.projects;
remote_participant.participant_index = participant_index;
- if location != remote_participant.location {
+ if location != remote_participant.location
+ || role != remote_participant.role
+ {
remote_participant.location = location;
+ remote_participant.role = role;
cx.emit(Event::ParticipantLocationChanged {
participant_id: peer_id,
});
@@ -789,6 +820,7 @@ impl Room {
peer_id,
projects: participant.projects,
location,
+ role,
muted: true,
speaking: false,
video_tracks: Default::default(),
@@ -1091,15 +1123,24 @@ impl Room {
) -> Task<Result<Model<Project>>> {
let client = self.client.clone();
let user_store = self.user_store.clone();
+ let role = self.local_participant.role;
cx.emit(Event::RemoteProjectJoined { project_id: id });
cx.spawn(move |this, mut cx| async move {
- let project =
- Project::remote(id, client, user_store, language_registry, fs, cx.clone()).await?;
+ let project = Project::remote(
+ id,
+ client,
+ user_store,
+ language_registry,
+ fs,
+ role,
+ cx.clone(),
+ )
+ .await?;
this.update(&mut cx, |this, cx| {
this.joined_projects.retain(|project| {
if let Some(project) = project.upgrade() {
- !project.read(cx).is_read_only()
+ !project.read(cx).is_disconnected()
} else {
false
}
@@ -1224,6 +1265,11 @@ impl Room {
.unwrap_or(false)
}
+ pub fn read_only(&self) -> bool {
+ !(self.local_participant().role == proto::ChannelRole::Member
+ || self.local_participant().role == proto::ChannelRole::Admin)
+ }
+
pub fn is_speaking(&self) -> bool {
self.live_kit
.as_ref()
@@ -62,7 +62,12 @@ impl ChannelBuffer {
.collect::<Result<Vec<_>, _>>()?;
let buffer = cx.new_model(|_| {
- language::Buffer::remote(response.buffer_id, response.replica_id as u16, base_text)
+ language::Buffer::remote(
+ response.buffer_id,
+ response.replica_id as u16,
+ channel.channel_buffer_capability(),
+ base_text,
+ )
})?;
buffer.update(&mut cx, |buffer, cx| buffer.apply_ops(operations, cx))??;
@@ -11,6 +11,7 @@ use gpui::{
AppContext, AsyncAppContext, Context, EventEmitter, Model, ModelContext, SharedString, Task,
WeakModel,
};
+use language::Capability;
use rpc::{
proto::{self, ChannelVisibility},
TypedEnvelope,
@@ -74,8 +75,12 @@ impl Channel {
slug.trim_matches(|c| c == '-').to_string()
}
- pub fn can_edit_notes(&self) -> bool {
- self.role == proto::ChannelRole::Member || self.role == proto::ChannelRole::Admin
+ pub fn channel_buffer_capability(&self) -> Capability {
+ if self.role == proto::ChannelRole::Member || self.role == proto::ChannelRole::Admin {
+ Capability::ReadWrite
+ } else {
+ Capability::ReadOnly
+ }
}
}
@@ -3,7 +3,7 @@ authors = ["Nathan Sobo <nathan@zed.dev>"]
default-run = "collab"
edition = "2021"
name = "collab"
-version = "0.33.0"
+version = "0.34.0"
publish = false
[[bin]]
@@ -13,6 +13,7 @@ metadata:
annotations:
service.beta.kubernetes.io/do-loadbalancer-tls-ports: "443"
service.beta.kubernetes.io/do-loadbalancer-certificate-id: ${ZED_DO_CERTIFICATE_ID}
+ service.beta.kubernetes.io/do-loadbalancer-disable-lets-encrypt-dns-records: true
spec:
type: LoadBalancer
selector:
@@ -7,6 +7,7 @@ metadata:
annotations:
service.beta.kubernetes.io/do-loadbalancer-tls-ports: "443"
service.beta.kubernetes.io/do-loadbalancer-certificate-id: ${ZED_DO_CERTIFICATE_ID}
+ service.beta.kubernetes.io/do-loadbalancer-disable-lets-encrypt-dns-records: true
spec:
type: LoadBalancer
selector:
@@ -161,7 +161,8 @@ CREATE TABLE "room_participants" (
"calling_user_id" INTEGER NOT NULL REFERENCES users (id),
"calling_connection_id" INTEGER NOT NULL,
"calling_connection_server_id" INTEGER REFERENCES servers (id) ON DELETE SET NULL,
- "participant_index" INTEGER
+ "participant_index" INTEGER,
+ "role" TEXT
);
CREATE UNIQUE INDEX "index_room_participants_on_user_id" ON "room_participants" ("user_id");
CREATE INDEX "index_room_participants_on_room_id" ON "room_participants" ("room_id");
@@ -0,0 +1 @@
+ALTER TABLE room_participants ADD COLUMN role TEXT;
@@ -132,6 +132,14 @@ impl ChannelRole {
Admin | Member | Banned => false,
}
}
+
+ pub fn can_share_projects(&self) -> bool {
+ use ChannelRole::*;
+ match self {
+ Admin | Member => true,
+ Guest | Banned => false,
+ }
+ }
}
impl From<proto::ChannelRole> for ChannelRole {
@@ -132,48 +132,49 @@ impl Database {
debug_assert!(
self.channel_role_for_user(&channel, user_id, &*tx).await? == role
);
- }
- }
-
- if channel.visibility == ChannelVisibility::Public {
- role = Some(ChannelRole::Guest);
- let channel_to_join = self
- .public_ancestors_including_self(&channel, &*tx)
- .await?
- .first()
- .cloned()
- .unwrap_or(channel.clone());
-
- channel_member::Entity::insert(channel_member::ActiveModel {
- id: ActiveValue::NotSet,
- channel_id: ActiveValue::Set(channel_to_join.id),
- user_id: ActiveValue::Set(user_id),
- accepted: ActiveValue::Set(true),
- role: ActiveValue::Set(ChannelRole::Guest),
- })
- .exec(&*tx)
- .await?;
+ } else if channel.visibility == ChannelVisibility::Public {
+ role = Some(ChannelRole::Guest);
+ let channel_to_join = self
+ .public_ancestors_including_self(&channel, &*tx)
+ .await?
+ .first()
+ .cloned()
+ .unwrap_or(channel.clone());
+
+ channel_member::Entity::insert(channel_member::ActiveModel {
+ id: ActiveValue::NotSet,
+ channel_id: ActiveValue::Set(channel_to_join.id),
+ user_id: ActiveValue::Set(user_id),
+ accepted: ActiveValue::Set(true),
+ role: ActiveValue::Set(ChannelRole::Guest),
+ })
+ .exec(&*tx)
+ .await?;
- accept_invite_result = Some(
- self.calculate_membership_updated(&channel_to_join, user_id, &*tx)
- .await?,
- );
+ accept_invite_result = Some(
+ self.calculate_membership_updated(&channel_to_join, user_id, &*tx)
+ .await?,
+ );
- debug_assert!(self.channel_role_for_user(&channel, user_id, &*tx).await? == role);
+ debug_assert!(
+ self.channel_role_for_user(&channel, user_id, &*tx).await? == role
+ );
+ }
}
if role.is_none() || role == Some(ChannelRole::Banned) {
Err(anyhow!("not allowed"))?
}
+ let role = role.unwrap();
let live_kit_room = format!("channel-{}", nanoid::nanoid!(30));
let room_id = self
.get_or_create_channel_room(channel_id, &live_kit_room, environment, &*tx)
.await?;
- self.join_channel_room_internal(room_id, user_id, connection, &*tx)
+ self.join_channel_room_internal(room_id, user_id, connection, role, &*tx)
.await
- .map(|jr| (jr, accept_invite_result, role.unwrap()))
+ .map(|jr| (jr, accept_invite_result, role))
})
.await
}
@@ -46,6 +46,13 @@ impl Database {
if participant.room_id != room_id {
return Err(anyhow!("shared project on unexpected room"))?;
}
+ if !participant
+ .role
+ .unwrap_or(ChannelRole::Member)
+ .can_share_projects()
+ {
+ return Err(anyhow!("guests cannot share projects"))?;
+ }
let project = project::ActiveModel {
room_id: ActiveValue::set(participant.room_id),
@@ -131,7 +131,12 @@ impl Database {
connection.owner_id as i32,
))),
participant_index: ActiveValue::set(Some(0)),
- ..Default::default()
+ role: ActiveValue::set(Some(ChannelRole::Admin)),
+
+ id: ActiveValue::NotSet,
+ location_kind: ActiveValue::NotSet,
+ location_project_id: ActiveValue::NotSet,
+ initial_project_id: ActiveValue::NotSet,
}
.insert(&*tx)
.await?;
@@ -151,6 +156,22 @@ impl Database {
initial_project_id: Option<ProjectId>,
) -> Result<RoomGuard<(proto::Room, proto::IncomingCall)>> {
self.room_transaction(room_id, |tx| async move {
+ let caller = room_participant::Entity::find()
+ .filter(
+ room_participant::Column::UserId
+ .eq(calling_user_id)
+ .and(room_participant::Column::RoomId.eq(room_id)),
+ )
+ .one(&*tx)
+ .await?
+ .ok_or_else(|| anyhow!("user is not in the room"))?;
+
+ let called_user_role = match caller.role.unwrap_or(ChannelRole::Member) {
+ ChannelRole::Admin | ChannelRole::Member => ChannelRole::Member,
+ ChannelRole::Guest => ChannelRole::Guest,
+ ChannelRole::Banned => return Err(anyhow!("banned users cannot invite").into()),
+ };
+
room_participant::ActiveModel {
room_id: ActiveValue::set(room_id),
user_id: ActiveValue::set(called_user_id),
@@ -162,7 +183,13 @@ impl Database {
calling_connection.owner_id as i32,
))),
initial_project_id: ActiveValue::set(initial_project_id),
- ..Default::default()
+ role: ActiveValue::set(Some(called_user_role)),
+
+ id: ActiveValue::NotSet,
+ answering_connection_id: ActiveValue::NotSet,
+ answering_connection_server_id: ActiveValue::NotSet,
+ location_kind: ActiveValue::NotSet,
+ location_project_id: ActiveValue::NotSet,
}
.insert(&*tx)
.await?;
@@ -384,6 +411,7 @@ impl Database {
room_id: RoomId,
user_id: UserId,
connection: ConnectionId,
+ role: ChannelRole,
tx: &DatabaseTransaction,
) -> Result<JoinRoom> {
let participant_index = self
@@ -404,7 +432,11 @@ impl Database {
connection.owner_id as i32,
))),
participant_index: ActiveValue::Set(Some(participant_index)),
- ..Default::default()
+ role: ActiveValue::set(Some(role)),
+ id: ActiveValue::NotSet,
+ location_kind: ActiveValue::NotSet,
+ location_project_id: ActiveValue::NotSet,
+ initial_project_id: ActiveValue::NotSet,
}])
.on_conflict(
OnConflict::columns([room_participant::Column::UserId])
@@ -413,6 +445,7 @@ impl Database {
room_participant::Column::AnsweringConnectionServerId,
room_participant::Column::AnsweringConnectionLost,
room_participant::Column::ParticipantIndex,
+ room_participant::Column::Role,
])
.to_owned(),
)
@@ -1126,6 +1159,7 @@ impl Database {
projects: Default::default(),
location: Some(proto::ParticipantLocation { variant: location }),
participant_index: participant_index as u32,
+ role: db_participant.role.unwrap_or(ChannelRole::Member).into(),
},
);
} else {
@@ -1,4 +1,4 @@
-use crate::db::{ProjectId, RoomId, RoomParticipantId, ServerId, UserId};
+use crate::db::{ChannelRole, ProjectId, RoomId, RoomParticipantId, ServerId, UserId};
use rpc::ConnectionId;
use sea_orm::entity::prelude::*;
@@ -19,6 +19,7 @@ pub struct Model {
pub calling_connection_id: i32,
pub calling_connection_server_id: Option<ServerId>,
pub participant_index: Option<i32>,
+ pub role: Option<ChannelRole>,
}
impl Model {
@@ -2,6 +2,7 @@ use call::Room;
use gpui::{Model, TestAppContext};
mod channel_buffer_tests;
+mod channel_guest_tests;
mod channel_message_tests;
mod channel_tests;
mod editor_tests;
@@ -0,0 +1,86 @@
+use crate::tests::TestServer;
+use call::ActiveCall;
+use gpui::{BackgroundExecutor, TestAppContext, VisualTestContext};
+use rpc::proto;
+use workspace::Workspace;
+
+#[gpui::test]
+async fn test_channel_guests(
+ executor: BackgroundExecutor,
+ cx_a: &mut TestAppContext,
+ cx_b: &mut TestAppContext,
+) {
+ let mut server = TestServer::start(executor.clone()).await;
+ let client_a = server.create_client(cx_a, "user_a").await;
+ let client_b = server.create_client(cx_b, "user_b").await;
+
+ let channel_id = server
+ .make_channel("the-channel", None, (&client_a, cx_a), &mut [])
+ .await;
+
+ client_a
+ .channel_store()
+ .update(cx_a, |channel_store, cx| {
+ channel_store.set_channel_visibility(channel_id, proto::ChannelVisibility::Public, cx)
+ })
+ .await
+ .unwrap();
+
+ client_a
+ .fs()
+ .insert_tree(
+ "/a",
+ serde_json::json!({
+ "a.txt": "a-contents",
+ }),
+ )
+ .await;
+
+ let active_call_a = cx_a.read(ActiveCall::global);
+
+ // Client A shares a project in the channel
+ active_call_a
+ .update(cx_a, |call, cx| call.join_channel(channel_id, cx))
+ .await
+ .unwrap();
+ let (project_a, _) = client_a.build_local_project("/a", cx_a).await;
+ let project_id = active_call_a
+ .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
+ .await
+ .unwrap();
+ cx_a.executor().run_until_parked();
+
+ // Client B joins channel A as a guest
+ cx_b.update(|cx| workspace::join_channel(channel_id, client_b.app_state.clone(), None, cx))
+ .await
+ .unwrap();
+
+ // b should be following a in the shared project.
+ // B is a guest,
+ cx_a.executor().run_until_parked();
+
+ // todo!() the test window does not call activation handlers
+ // correctly yet, so this API does not work.
+ // let project_b = active_call_b.read_with(cx_b, |call, _| {
+ // call.location()
+ // .unwrap()
+ // .upgrade()
+ // .expect("should not be weak")
+ // });
+
+ let window_b = cx_b.update(|cx| cx.active_window().unwrap());
+ let cx_b = &mut VisualTestContext::from_window(window_b, cx_b);
+
+ let workspace_b = window_b
+ .downcast::<Workspace>()
+ .unwrap()
+ .root_view(cx_b)
+ .unwrap();
+ let project_b = workspace_b.update(cx_b, |workspace, _| workspace.project().clone());
+
+ assert_eq!(
+ project_b.read_with(cx_b, |project, _| project.remote_id()),
+ Some(project_id),
+ );
+ assert!(project_b.read_with(cx_b, |project, _| project.is_read_only()))
+}
@@ -1,1889 +1,1884 @@
-//todo(partially ported)
-// use std::{
-// path::Path,
-// sync::{
-// atomic::{self, AtomicBool, AtomicUsize},
-// Arc,
-// },
-// };
-
-// use call::ActiveCall;
-// use editor::{
-// test::editor_test_context::{AssertionContextManager, EditorTestContext},
-// Anchor, ConfirmCodeAction, ConfirmCompletion, ConfirmRename, Editor, Redo, Rename,
-// ToggleCodeActions, Undo,
-// };
-// use gpui::{BackgroundExecutor, TestAppContext, VisualContext, VisualTestContext};
-// use indoc::indoc;
-// use language::{
-// language_settings::{AllLanguageSettings, InlayHintSettings},
-// tree_sitter_rust, FakeLspAdapter, Language, LanguageConfig,
-// };
-// use rpc::RECEIVE_TIMEOUT;
-// use serde_json::json;
-// use settings::SettingsStore;
-// use text::Point;
-// use workspace::Workspace;
-
-// use crate::{rpc::RECONNECT_TIMEOUT, tests::TestServer};
-
-// #[gpui::test(iterations = 10)]
-// async fn test_host_disconnect(
-// executor: BackgroundExecutor,
-// cx_a: &mut TestAppContext,
-// cx_b: &mut TestAppContext,
-// cx_c: &mut TestAppContext,
-// ) {
-// let mut server = TestServer::start(executor).await;
-// let client_a = server.create_client(cx_a, "user_a").await;
-// let client_b = server.create_client(cx_b, "user_b").await;
-// let client_c = server.create_client(cx_c, "user_c").await;
-// server
-// .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b), (&client_c, cx_c)])
-// .await;
-
-// cx_b.update(editor::init);
-
-// client_a
-// .fs()
-// .insert_tree(
-// "/a",
-// serde_json::json!({
-// "a.txt": "a-contents",
-// "b.txt": "b-contents",
-// }),
-// )
-// .await;
-
-// let active_call_a = cx_a.read(ActiveCall::global);
-// let (project_a, worktree_id) = client_a.build_local_project("/a", cx_a).await;
-
-// let worktree_a = project_a.read_with(cx_a, |project, cx| project.worktrees().next().unwrap());
-// let project_id = active_call_a
-// .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
-// .await
-// .unwrap();
-
-// let project_b = client_b.build_remote_project(project_id, cx_b).await;
-// executor.run_until_parked();
-
-// assert!(worktree_a.read_with(cx_a, |tree, _| tree.as_local().unwrap().is_shared()));
-
-// let workspace_b =
-// cx_b.add_window(|cx| Workspace::new(0, project_b.clone(), client_b.app_state.clone(), cx));
-// let cx_b = &mut VisualTestContext::from_window(*workspace_b, cx_b);
-
-// let editor_b = workspace_b
-// .update(cx_b, |workspace, cx| {
-// workspace.open_path((worktree_id, "b.txt"), None, true, cx)
-// })
-// .unwrap()
-// .await
-// .unwrap()
-// .downcast::<Editor>()
-// .unwrap();
-
-// //TODO: focus
-// assert!(cx_b.update_view(&editor_b, |editor, cx| editor.is_focused(cx)));
-// editor_b.update(cx_b, |editor, cx| editor.insert("X", cx));
-// //todo(is_edited)
-// // assert!(workspace_b.is_edited(cx_b));
-
-// // Drop client A's connection. Collaborators should disappear and the project should not be shown as shared.
-// server.forbid_connections();
-// server.disconnect_client(client_a.peer_id().unwrap());
-// executor.advance_clock(RECEIVE_TIMEOUT + RECONNECT_TIMEOUT);
-
-// project_a.read_with(cx_a, |project, _| project.collaborators().is_empty());
-
-// project_a.read_with(cx_a, |project, _| assert!(!project.is_shared()));
-
-// project_b.read_with(cx_b, |project, _| project.is_read_only());
-
-// assert!(worktree_a.read_with(cx_a, |tree, _| !tree.as_local().unwrap().is_shared()));
-
-// // Ensure client B's edited state is reset and that the whole window is blurred.
-
-// workspace_b.update(cx_b, |_, cx| {
-// assert_eq!(cx.focused_view_id(), None);
-// });
-// // assert!(!workspace_b.is_edited(cx_b));
-
-// // Ensure client B is not prompted to save edits when closing window after disconnecting.
-// let can_close = workspace_b
-// .update(cx_b, |workspace, cx| workspace.prepare_to_close(true, cx))
-// .await
-// .unwrap();
-// assert!(can_close);
-
-// // Allow client A to reconnect to the server.
-// server.allow_connections();
-// executor.advance_clock(RECEIVE_TIMEOUT);
-
-// // Client B calls client A again after they reconnected.
-// let active_call_b = cx_b.read(ActiveCall::global);
-// active_call_b
-// .update(cx_b, |call, cx| {
-// call.invite(client_a.user_id().unwrap(), None, cx)
-// })
-// .await
-// .unwrap();
-// executor.run_until_parked();
-// active_call_a
-// .update(cx_a, |call, cx| call.accept_incoming(cx))
-// .await
-// .unwrap();
-
-// active_call_a
-// .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
-// .await
-// .unwrap();
-
-// // Drop client A's connection again. We should still unshare it successfully.
-// server.forbid_connections();
-// server.disconnect_client(client_a.peer_id().unwrap());
-// executor.advance_clock(RECEIVE_TIMEOUT + RECONNECT_TIMEOUT);
-
-// project_a.read_with(cx_a, |project, _| assert!(!project.is_shared()));
-// }
-
-// #[gpui::test]
-// async fn test_newline_above_or_below_does_not_move_guest_cursor(
-// executor: BackgroundExecutor,
-// cx_a: &mut TestAppContext,
-// cx_b: &mut TestAppContext,
-// ) {
-// let mut server = TestServer::start(&executor).await;
-// let client_a = server.create_client(cx_a, "user_a").await;
-// let client_b = server.create_client(cx_b, "user_b").await;
-// server
-// .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
-// .await;
-// let active_call_a = cx_a.read(ActiveCall::global);
-
-// client_a
-// .fs()
-// .insert_tree("/dir", json!({ "a.txt": "Some text\n" }))
-// .await;
-// let (project_a, worktree_id) = client_a.build_local_project("/dir", cx_a).await;
-// let project_id = active_call_a
-// .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
-// .await
-// .unwrap();
-
-// let project_b = client_b.build_remote_project(project_id, cx_b).await;
-
-// // Open a buffer as client A
-// let buffer_a = project_a
-// .update(cx_a, |p, cx| p.open_buffer((worktree_id, "a.txt"), cx))
-// .await
-// .unwrap();
-// let window_a = cx_a.add_empty_window();
-// let editor_a =
-// window_a.build_view(cx_a, |cx| Editor::for_buffer(buffer_a, Some(project_a), cx));
-// let mut editor_cx_a = EditorTestContext {
-// cx: cx_a,
-// window: window_a.into(),
-// editor: editor_a,
-// assertion_cx: AssertionContextManager::new(),
-// };
-
-// // Open a buffer as client B
-// let buffer_b = project_b
-// .update(cx_b, |p, cx| p.open_buffer((worktree_id, "a.txt"), cx))
-// .await
-// .unwrap();
-// let window_b = cx_b.add_empty_window();
-// let editor_b =
-// window_b.build_view(cx_b, |cx| Editor::for_buffer(buffer_b, Some(project_b), cx));
-// let mut editor_cx_b = EditorTestContext {
-// cx: cx_b,
-// window: window_b.into(),
-// editor: editor_b,
-// assertion_cx: AssertionContextManager::new(),
-// };
-
-// // Test newline above
-// editor_cx_a.set_selections_state(indoc! {"
-// Some textˇ
-// "});
-// editor_cx_b.set_selections_state(indoc! {"
-// Some textˇ
-// "});
-// editor_cx_a.update_editor(|editor, cx| editor.newline_above(&editor::NewlineAbove, cx));
-// executor.run_until_parked();
-// editor_cx_a.assert_editor_state(indoc! {"
-// ˇ
-// Some text
-// "});
-// editor_cx_b.assert_editor_state(indoc! {"
-
-// Some textˇ
-// "});
-
-// // Test newline below
-// editor_cx_a.set_selections_state(indoc! {"
-
-// Some textˇ
-// "});
-// editor_cx_b.set_selections_state(indoc! {"
-
-// Some textˇ
-// "});
-// editor_cx_a.update_editor(|editor, cx| editor.newline_below(&editor::NewlineBelow, cx));
-// executor.run_until_parked();
-// editor_cx_a.assert_editor_state(indoc! {"
-
-// Some text
-// ˇ
-// "});
-// editor_cx_b.assert_editor_state(indoc! {"
-
-// Some textˇ
-
-// "});
-// }
-
-// #[gpui::test(iterations = 10)]
-// async fn test_collaborating_with_completion(
-// executor: BackgroundExecutor,
-// cx_a: &mut TestAppContext,
-// cx_b: &mut TestAppContext,
-// ) {
-// let mut server = TestServer::start(&executor).await;
-// let client_a = server.create_client(cx_a, "user_a").await;
-// let client_b = server.create_client(cx_b, "user_b").await;
-// server
-// .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
-// .await;
-// let active_call_a = cx_a.read(ActiveCall::global);
-
-// // Set up a fake language server.
-// let mut language = Language::new(
-// LanguageConfig {
-// name: "Rust".into(),
-// path_suffixes: vec!["rs".to_string()],
-// ..Default::default()
-// },
-// Some(tree_sitter_rust::language()),
-// );
-// let mut fake_language_servers = language
-// .set_fake_lsp_adapter(Arc::new(FakeLspAdapter {
-// capabilities: lsp::ServerCapabilities {
-// completion_provider: Some(lsp::CompletionOptions {
-// trigger_characters: Some(vec![".".to_string()]),
-// resolve_provider: Some(true),
-// ..Default::default()
-// }),
-// ..Default::default()
-// },
-// ..Default::default()
-// }))
-// .await;
-// client_a.language_registry().add(Arc::new(language));
-
-// client_a
-// .fs()
-// .insert_tree(
-// "/a",
-// json!({
-// "main.rs": "fn main() { a }",
-// "other.rs": "",
-// }),
-// )
-// .await;
-// let (project_a, worktree_id) = client_a.build_local_project("/a", cx_a).await;
-// let project_id = active_call_a
-// .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
-// .await
-// .unwrap();
-// let project_b = client_b.build_remote_project(project_id, cx_b).await;
-
-// // Open a file in an editor as the guest.
-// let buffer_b = project_b
-// .update(cx_b, |p, cx| p.open_buffer((worktree_id, "main.rs"), cx))
-// .await
-// .unwrap();
-// let window_b = cx_b.add_empty_window();
-// let editor_b = window_b.build_view(cx_b, |cx| {
-// Editor::for_buffer(buffer_b.clone(), Some(project_b.clone()), cx)
-// });
-
-// let fake_language_server = fake_language_servers.next().await.unwrap();
-// cx_a.foreground().run_until_parked();
-
-// buffer_b.read_with(cx_b, |buffer, _| {
-// assert!(!buffer.completion_triggers().is_empty())
-// });
-
-// // Type a completion trigger character as the guest.
-// editor_b.update(cx_b, |editor, cx| {
-// editor.change_selections(None, cx, |s| s.select_ranges([13..13]));
-// editor.handle_input(".", cx);
-// cx.focus(&editor_b);
-// });
-
-// // Receive a completion request as the host's language server.
-// // Return some completions from the host's language server.
-// cx_a.foreground().start_waiting();
-// fake_language_server
-// .handle_request::<lsp::request::Completion, _, _>(|params, _| async move {
-// assert_eq!(
-// params.text_document_position.text_document.uri,
-// lsp::Url::from_file_path("/a/main.rs").unwrap(),
-// );
-// assert_eq!(
-// params.text_document_position.position,
-// lsp::Position::new(0, 14),
-// );
-
-// Ok(Some(lsp::CompletionResponse::Array(vec![
-// lsp::CompletionItem {
-// label: "first_method(…)".into(),
-// detail: Some("fn(&mut self, B) -> C".into()),
-// text_edit: Some(lsp::CompletionTextEdit::Edit(lsp::TextEdit {
-// new_text: "first_method($1)".to_string(),
-// range: lsp::Range::new(
-// lsp::Position::new(0, 14),
-// lsp::Position::new(0, 14),
-// ),
-// })),
-// insert_text_format: Some(lsp::InsertTextFormat::SNIPPET),
-// ..Default::default()
-// },
-// lsp::CompletionItem {
-// label: "second_method(…)".into(),
-// detail: Some("fn(&mut self, C) -> D<E>".into()),
-// text_edit: Some(lsp::CompletionTextEdit::Edit(lsp::TextEdit {
-// new_text: "second_method()".to_string(),
-// range: lsp::Range::new(
-// lsp::Position::new(0, 14),
-// lsp::Position::new(0, 14),
-// ),
-// })),
-// insert_text_format: Some(lsp::InsertTextFormat::SNIPPET),
-// ..Default::default()
-// },
-// ])))
-// })
-// .next()
-// .await
-// .unwrap();
-// cx_a.foreground().finish_waiting();
-
-// // Open the buffer on the host.
-// let buffer_a = project_a
-// .update(cx_a, |p, cx| p.open_buffer((worktree_id, "main.rs"), cx))
-// .await
-// .unwrap();
-// cx_a.foreground().run_until_parked();
-
-// buffer_a.read_with(cx_a, |buffer, _| {
-// assert_eq!(buffer.text(), "fn main() { a. }")
-// });
-
-// // Confirm a completion on the guest.
-
-// editor_b.read_with(cx_b, |editor, _| assert!(editor.context_menu_visible()));
-// editor_b.update(cx_b, |editor, cx| {
-// editor.confirm_completion(&ConfirmCompletion { item_ix: Some(0) }, cx);
-// assert_eq!(editor.text(cx), "fn main() { a.first_method() }");
-// });
-
-// // Return a resolved completion from the host's language server.
-// // The resolved completion has an additional text edit.
-// fake_language_server.handle_request::<lsp::request::ResolveCompletionItem, _, _>(
-// |params, _| async move {
-// assert_eq!(params.label, "first_method(…)");
-// Ok(lsp::CompletionItem {
-// label: "first_method(…)".into(),
-// detail: Some("fn(&mut self, B) -> C".into()),
-// text_edit: Some(lsp::CompletionTextEdit::Edit(lsp::TextEdit {
-// new_text: "first_method($1)".to_string(),
-// range: lsp::Range::new(lsp::Position::new(0, 14), lsp::Position::new(0, 14)),
-// })),
-// additional_text_edits: Some(vec![lsp::TextEdit {
-// new_text: "use d::SomeTrait;\n".to_string(),
-// range: lsp::Range::new(lsp::Position::new(0, 0), lsp::Position::new(0, 0)),
-// }]),
-// insert_text_format: Some(lsp::InsertTextFormat::SNIPPET),
-// ..Default::default()
-// })
-// },
-// );
-
-// // The additional edit is applied.
-// cx_a.executor().run_until_parked();
-
-// buffer_a.read_with(cx_a, |buffer, _| {
-// assert_eq!(
-// buffer.text(),
-// "use d::SomeTrait;\nfn main() { a.first_method() }"
-// );
-// });
-
-// buffer_b.read_with(cx_b, |buffer, _| {
-// assert_eq!(
-// buffer.text(),
-// "use d::SomeTrait;\nfn main() { a.first_method() }"
-// );
-// });
-// }
-
-// #[gpui::test(iterations = 10)]
-// async fn test_collaborating_with_code_actions(
-// executor: BackgroundExecutor,
-// cx_a: &mut TestAppContext,
-// cx_b: &mut TestAppContext,
-// ) {
-// let mut server = TestServer::start(&executor).await;
-// let client_a = server.create_client(cx_a, "user_a").await;
-// //
-// let client_b = server.create_client(cx_b, "user_b").await;
-// server
-// .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
-// .await;
-// let active_call_a = cx_a.read(ActiveCall::global);
-
-// cx_b.update(editor::init);
-
-// // Set up a fake language server.
-// let mut language = Language::new(
-// LanguageConfig {
-// name: "Rust".into(),
-// path_suffixes: vec!["rs".to_string()],
-// ..Default::default()
-// },
-// Some(tree_sitter_rust::language()),
-// );
-// let mut fake_language_servers = language.set_fake_lsp_adapter(Default::default()).await;
-// client_a.language_registry().add(Arc::new(language));
-
-// client_a
-// .fs()
-// .insert_tree(
-// "/a",
-// json!({
-// "main.rs": "mod other;\nfn main() { let foo = other::foo(); }",
-// "other.rs": "pub fn foo() -> usize { 4 }",
-// }),
-// )
-// .await;
-// let (project_a, worktree_id) = client_a.build_local_project("/a", cx_a).await;
-// let project_id = active_call_a
-// .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
-// .await
-// .unwrap();
-
-// // Join the project as client B.
-// let project_b = client_b.build_remote_project(project_id, cx_b).await;
-// let window_b =
-// cx_b.add_window(|cx| Workspace::new(0, project_b.clone(), client_b.app_state.clone(), cx));
-// let workspace_b = window_b.root(cx_b);
-// let editor_b = workspace_b
-// .update(cx_b, |workspace, cx| {
-// workspace.open_path((worktree_id, "main.rs"), None, true, cx)
-// })
-// .await
-// .unwrap()
-// .downcast::<Editor>()
-// .unwrap();
-
-// let mut fake_language_server = fake_language_servers.next().await.unwrap();
-// let mut requests = fake_language_server
-// .handle_request::<lsp::request::CodeActionRequest, _, _>(|params, _| async move {
-// assert_eq!(
-// params.text_document.uri,
-// lsp::Url::from_file_path("/a/main.rs").unwrap(),
-// );
-// assert_eq!(params.range.start, lsp::Position::new(0, 0));
-// assert_eq!(params.range.end, lsp::Position::new(0, 0));
-// Ok(None)
-// });
-// executor.advance_clock(editor::CODE_ACTIONS_DEBOUNCE_TIMEOUT * 2);
-// requests.next().await;
-
-// // Move cursor to a location that contains code actions.
-// editor_b.update(cx_b, |editor, cx| {
-// editor.change_selections(None, cx, |s| {
-// s.select_ranges([Point::new(1, 31)..Point::new(1, 31)])
-// });
-// cx.focus(&editor_b);
-// });
-
-// let mut requests = fake_language_server
-// .handle_request::<lsp::request::CodeActionRequest, _, _>(|params, _| async move {
-// assert_eq!(
-// params.text_document.uri,
-// lsp::Url::from_file_path("/a/main.rs").unwrap(),
-// );
-// assert_eq!(params.range.start, lsp::Position::new(1, 31));
-// assert_eq!(params.range.end, lsp::Position::new(1, 31));
-
-// Ok(Some(vec![lsp::CodeActionOrCommand::CodeAction(
-// lsp::CodeAction {
-// title: "Inline into all callers".to_string(),
-// edit: Some(lsp::WorkspaceEdit {
-// changes: Some(
-// [
-// (
-// lsp::Url::from_file_path("/a/main.rs").unwrap(),
-// vec![lsp::TextEdit::new(
-// lsp::Range::new(
-// lsp::Position::new(1, 22),
-// lsp::Position::new(1, 34),
-// ),
-// "4".to_string(),
-// )],
-// ),
-// (
-// lsp::Url::from_file_path("/a/other.rs").unwrap(),
-// vec![lsp::TextEdit::new(
-// lsp::Range::new(
-// lsp::Position::new(0, 0),
-// lsp::Position::new(0, 27),
-// ),
-// "".to_string(),
-// )],
-// ),
-// ]
-// .into_iter()
-// .collect(),
-// ),
-// ..Default::default()
-// }),
-// data: Some(json!({
-// "codeActionParams": {
-// "range": {
-// "start": {"line": 1, "column": 31},
-// "end": {"line": 1, "column": 31},
-// }
-// }
-// })),
-// ..Default::default()
-// },
-// )]))
-// });
-// executor.advance_clock(editor::CODE_ACTIONS_DEBOUNCE_TIMEOUT * 2);
-// requests.next().await;
-
-// // Toggle code actions and wait for them to display.
-// editor_b.update(cx_b, |editor, cx| {
-// editor.toggle_code_actions(
-// &ToggleCodeActions {
-// deployed_from_indicator: false,
-// },
-// cx,
-// );
-// });
-// cx_a.foreground().run_until_parked();
-
-// editor_b.read_with(cx_b, |editor, _| assert!(editor.context_menu_visible()));
-
-// fake_language_server.remove_request_handler::<lsp::request::CodeActionRequest>();
-
-// // Confirming the code action will trigger a resolve request.
-// let confirm_action = workspace_b
-// .update(cx_b, |workspace, cx| {
-// Editor::confirm_code_action(workspace, &ConfirmCodeAction { item_ix: Some(0) }, cx)
-// })
-// .unwrap();
-// fake_language_server.handle_request::<lsp::request::CodeActionResolveRequest, _, _>(
-// |_, _| async move {
-// Ok(lsp::CodeAction {
-// title: "Inline into all callers".to_string(),
-// edit: Some(lsp::WorkspaceEdit {
-// changes: Some(
-// [
-// (
-// lsp::Url::from_file_path("/a/main.rs").unwrap(),
-// vec![lsp::TextEdit::new(
-// lsp::Range::new(
-// lsp::Position::new(1, 22),
-// lsp::Position::new(1, 34),
-// ),
-// "4".to_string(),
-// )],
-// ),
-// (
-// lsp::Url::from_file_path("/a/other.rs").unwrap(),
-// vec![lsp::TextEdit::new(
-// lsp::Range::new(
-// lsp::Position::new(0, 0),
-// lsp::Position::new(0, 27),
-// ),
-// "".to_string(),
-// )],
-// ),
-// ]
-// .into_iter()
-// .collect(),
-// ),
-// ..Default::default()
-// }),
-// ..Default::default()
-// })
-// },
-// );
-
-// // After the action is confirmed, an editor containing both modified files is opened.
-// confirm_action.await.unwrap();
-
-// let code_action_editor = workspace_b.read_with(cx_b, |workspace, cx| {
-// workspace
-// .active_item(cx)
-// .unwrap()
-// .downcast::<Editor>()
-// .unwrap()
-// });
-// code_action_editor.update(cx_b, |editor, cx| {
-// assert_eq!(editor.text(cx), "mod other;\nfn main() { let foo = 4; }\n");
-// editor.undo(&Undo, cx);
-// assert_eq!(
-// editor.text(cx),
-// "mod other;\nfn main() { let foo = other::foo(); }\npub fn foo() -> usize { 4 }"
-// );
-// editor.redo(&Redo, cx);
-// assert_eq!(editor.text(cx), "mod other;\nfn main() { let foo = 4; }\n");
-// });
-// }
-
-// #[gpui::test(iterations = 10)]
-// async fn test_collaborating_with_renames(
-// executor: BackgroundExecutor,
-// cx_a: &mut TestAppContext,
-// cx_b: &mut TestAppContext,
-// ) {
-// let mut server = TestServer::start(&executor).await;
-// let client_a = server.create_client(cx_a, "user_a").await;
-// let client_b = server.create_client(cx_b, "user_b").await;
-// server
-// .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
-// .await;
-// let active_call_a = cx_a.read(ActiveCall::global);
-
-// cx_b.update(editor::init);
-
-// // Set up a fake language server.
-// let mut language = Language::new(
-// LanguageConfig {
-// name: "Rust".into(),
-// path_suffixes: vec!["rs".to_string()],
-// ..Default::default()
-// },
-// Some(tree_sitter_rust::language()),
-// );
-// let mut fake_language_servers = language
-// .set_fake_lsp_adapter(Arc::new(FakeLspAdapter {
-// capabilities: lsp::ServerCapabilities {
-// rename_provider: Some(lsp::OneOf::Right(lsp::RenameOptions {
-// prepare_provider: Some(true),
-// work_done_progress_options: Default::default(),
-// })),
-// ..Default::default()
-// },
-// ..Default::default()
-// }))
-// .await;
-// client_a.language_registry().add(Arc::new(language));
-
-// client_a
-// .fs()
-// .insert_tree(
-// "/dir",
-// json!({
-// "one.rs": "const ONE: usize = 1;",
-// "two.rs": "const TWO: usize = one::ONE + one::ONE;"
-// }),
-// )
-// .await;
-// let (project_a, worktree_id) = client_a.build_local_project("/dir", cx_a).await;
-// let project_id = active_call_a
-// .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
-// .await
-// .unwrap();
-// let project_b = client_b.build_remote_project(project_id, cx_b).await;
-
-// let window_b =
-// cx_b.add_window(|cx| Workspace::new(0, project_b.clone(), client_b.app_state.clone(), cx));
-// let workspace_b = window_b.root(cx_b);
-// let editor_b = workspace_b
-// .update(cx_b, |workspace, cx| {
-// workspace.open_path((worktree_id, "one.rs"), None, true, cx)
-// })
-// .await
-// .unwrap()
-// .downcast::<Editor>()
-// .unwrap();
-// let fake_language_server = fake_language_servers.next().await.unwrap();
-
-// // Move cursor to a location that can be renamed.
-// let prepare_rename = editor_b.update(cx_b, |editor, cx| {
-// editor.change_selections(None, cx, |s| s.select_ranges([7..7]));
-// editor.rename(&Rename, cx).unwrap()
-// });
-
-// fake_language_server
-// .handle_request::<lsp::request::PrepareRenameRequest, _, _>(|params, _| async move {
-// assert_eq!(params.text_document.uri.as_str(), "file:///dir/one.rs");
-// assert_eq!(params.position, lsp::Position::new(0, 7));
-// Ok(Some(lsp::PrepareRenameResponse::Range(lsp::Range::new(
-// lsp::Position::new(0, 6),
-// lsp::Position::new(0, 9),
-// ))))
-// })
-// .next()
-// .await
-// .unwrap();
-// prepare_rename.await.unwrap();
-// editor_b.update(cx_b, |editor, cx| {
-// use editor::ToOffset;
-// let rename = editor.pending_rename().unwrap();
-// let buffer = editor.buffer().read(cx).snapshot(cx);
-// assert_eq!(
-// rename.range.start.to_offset(&buffer)..rename.range.end.to_offset(&buffer),
-// 6..9
-// );
-// rename.editor.update(cx, |rename_editor, cx| {
-// rename_editor.buffer().update(cx, |rename_buffer, cx| {
-// rename_buffer.edit([(0..3, "THREE")], None, cx);
-// });
-// });
-// });
-
-// let confirm_rename = workspace_b.update(cx_b, |workspace, cx| {
-// Editor::confirm_rename(workspace, &ConfirmRename, cx).unwrap()
-// });
-// fake_language_server
-// .handle_request::<lsp::request::Rename, _, _>(|params, _| async move {
-// assert_eq!(
-// params.text_document_position.text_document.uri.as_str(),
-// "file:///dir/one.rs"
-// );
-// assert_eq!(
-// params.text_document_position.position,
-// lsp::Position::new(0, 6)
-// );
-// assert_eq!(params.new_name, "THREE");
-// Ok(Some(lsp::WorkspaceEdit {
-// changes: Some(
-// [
-// (
-// lsp::Url::from_file_path("/dir/one.rs").unwrap(),
-// vec![lsp::TextEdit::new(
-// lsp::Range::new(lsp::Position::new(0, 6), lsp::Position::new(0, 9)),
-// "THREE".to_string(),
-// )],
-// ),
-// (
-// lsp::Url::from_file_path("/dir/two.rs").unwrap(),
-// vec![
-// lsp::TextEdit::new(
-// lsp::Range::new(
-// lsp::Position::new(0, 24),
-// lsp::Position::new(0, 27),
-// ),
-// "THREE".to_string(),
-// ),
-// lsp::TextEdit::new(
-// lsp::Range::new(
-// lsp::Position::new(0, 35),
-// lsp::Position::new(0, 38),
-// ),
-// "THREE".to_string(),
-// ),
-// ],
-// ),
-// ]
-// .into_iter()
-// .collect(),
-// ),
-// ..Default::default()
-// }))
-// })
-// .next()
-// .await
-// .unwrap();
-// confirm_rename.await.unwrap();
-
-// let rename_editor = workspace_b.read_with(cx_b, |workspace, cx| {
-// workspace
-// .active_item(cx)
-// .unwrap()
-// .downcast::<Editor>()
-// .unwrap()
-// });
-// rename_editor.update(cx_b, |editor, cx| {
-// assert_eq!(
-// editor.text(cx),
-// "const THREE: usize = 1;\nconst TWO: usize = one::THREE + one::THREE;"
-// );
-// editor.undo(&Undo, cx);
-// assert_eq!(
-// editor.text(cx),
-// "const ONE: usize = 1;\nconst TWO: usize = one::ONE + one::ONE;"
-// );
-// editor.redo(&Redo, cx);
-// assert_eq!(
-// editor.text(cx),
-// "const THREE: usize = 1;\nconst TWO: usize = one::THREE + one::THREE;"
-// );
-// });
-
-// // Ensure temporary rename edits cannot be undone/redone.
-// editor_b.update(cx_b, |editor, cx| {
-// editor.undo(&Undo, cx);
-// assert_eq!(editor.text(cx), "const ONE: usize = 1;");
-// editor.undo(&Undo, cx);
-// assert_eq!(editor.text(cx), "const ONE: usize = 1;");
-// editor.redo(&Redo, cx);
-// assert_eq!(editor.text(cx), "const THREE: usize = 1;");
-// })
-// }
-
-// #[gpui::test(iterations = 10)]
-// async fn test_language_server_statuses(
-// executor: BackgroundExecutor,
-// cx_a: &mut TestAppContext,
-// cx_b: &mut TestAppContext,
-// ) {
-// let mut server = TestServer::start(&executor).await;
-// let client_a = server.create_client(cx_a, "user_a").await;
-// let client_b = server.create_client(cx_b, "user_b").await;
-// server
-// .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
-// .await;
-// let active_call_a = cx_a.read(ActiveCall::global);
-
-// cx_b.update(editor::init);
-
-// // Set up a fake language server.
-// let mut language = Language::new(
-// LanguageConfig {
-// name: "Rust".into(),
-// path_suffixes: vec!["rs".to_string()],
-// ..Default::default()
-// },
-// Some(tree_sitter_rust::language()),
-// );
-// let mut fake_language_servers = language
-// .set_fake_lsp_adapter(Arc::new(FakeLspAdapter {
-// name: "the-language-server",
-// ..Default::default()
-// }))
-// .await;
-// client_a.language_registry().add(Arc::new(language));
-
-// client_a
-// .fs()
-// .insert_tree(
-// "/dir",
-// json!({
-// "main.rs": "const ONE: usize = 1;",
-// }),
-// )
-// .await;
-// let (project_a, worktree_id) = client_a.build_local_project("/dir", cx_a).await;
-
-// let _buffer_a = project_a
-// .update(cx_a, |p, cx| p.open_buffer((worktree_id, "main.rs"), cx))
-// .await
-// .unwrap();
-
-// let fake_language_server = fake_language_servers.next().await.unwrap();
-// fake_language_server.start_progress("the-token").await;
-// fake_language_server.notify::<lsp::notification::Progress>(lsp::ProgressParams {
-// token: lsp::NumberOrString::String("the-token".to_string()),
-// value: lsp::ProgressParamsValue::WorkDone(lsp::WorkDoneProgress::Report(
-// lsp::WorkDoneProgressReport {
-// message: Some("the-message".to_string()),
-// ..Default::default()
-// },
-// )),
-// });
-// executor.run_until_parked();
-
-// project_a.read_with(cx_a, |project, _| {
-// let status = project.language_server_statuses().next().unwrap();
-// assert_eq!(status.name, "the-language-server");
-// assert_eq!(status.pending_work.len(), 1);
-// assert_eq!(
-// status.pending_work["the-token"].message.as_ref().unwrap(),
-// "the-message"
-// );
-// });
-
-// let project_id = active_call_a
-// .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
-// .await
-// .unwrap();
-// executor.run_until_parked();
-// let project_b = client_b.build_remote_project(project_id, cx_b).await;
-
-// project_b.read_with(cx_b, |project, _| {
-// let status = project.language_server_statuses().next().unwrap();
-// assert_eq!(status.name, "the-language-server");
-// });
-
-// fake_language_server.notify::<lsp::notification::Progress>(lsp::ProgressParams {
-// token: lsp::NumberOrString::String("the-token".to_string()),
-// value: lsp::ProgressParamsValue::WorkDone(lsp::WorkDoneProgress::Report(
-// lsp::WorkDoneProgressReport {
-// message: Some("the-message-2".to_string()),
-// ..Default::default()
-// },
-// )),
-// });
-// executor.run_until_parked();
-
-// project_a.read_with(cx_a, |project, _| {
-// let status = project.language_server_statuses().next().unwrap();
-// assert_eq!(status.name, "the-language-server");
-// assert_eq!(status.pending_work.len(), 1);
-// assert_eq!(
-// status.pending_work["the-token"].message.as_ref().unwrap(),
-// "the-message-2"
-// );
-// });
-
-// project_b.read_with(cx_b, |project, _| {
-// let status = project.language_server_statuses().next().unwrap();
-// assert_eq!(status.name, "the-language-server");
-// assert_eq!(status.pending_work.len(), 1);
-// assert_eq!(
-// status.pending_work["the-token"].message.as_ref().unwrap(),
-// "the-message-2"
-// );
-// });
-// }
-
-// #[gpui::test(iterations = 10)]
-// async fn test_share_project(
-// executor: BackgroundExecutor,
-// cx_a: &mut TestAppContext,
-// cx_b: &mut TestAppContext,
-// cx_c: &mut TestAppContext,
-// ) {
-// let window_b = cx_b.add_empty_window();
-// let mut server = TestServer::start(executor).await;
-// let client_a = server.create_client(cx_a, "user_a").await;
-// let client_b = server.create_client(cx_b, "user_b").await;
-// let client_c = server.create_client(cx_c, "user_c").await;
-// server
-// .make_contacts(&mut [(&client_a, cx_a), (&client_b, cx_b), (&client_c, cx_c)])
-// .await;
-// let active_call_a = cx_a.read(ActiveCall::global);
-// let active_call_b = cx_b.read(ActiveCall::global);
-// let active_call_c = cx_c.read(ActiveCall::global);
-
-// client_a
-// .fs()
-// .insert_tree(
-// "/a",
-// json!({
-// ".gitignore": "ignored-dir",
-// "a.txt": "a-contents",
-// "b.txt": "b-contents",
-// "ignored-dir": {
-// "c.txt": "",
-// "d.txt": "",
-// }
-// }),
-// )
-// .await;
-
-// // Invite client B to collaborate on a project
-// let (project_a, worktree_id) = client_a.build_local_project("/a", cx_a).await;
-// active_call_a
-// .update(cx_a, |call, cx| {
-// call.invite(client_b.user_id().unwrap(), Some(project_a.clone()), cx)
-// })
-// .await
-// .unwrap();
-
-// // Join that project as client B
-
-// let incoming_call_b = active_call_b.read_with(cx_b, |call, _| call.incoming());
-// executor.run_until_parked();
-// let call = incoming_call_b.borrow().clone().unwrap();
-// assert_eq!(call.calling_user.github_login, "user_a");
-// let initial_project = call.initial_project.unwrap();
-// active_call_b
-// .update(cx_b, |call, cx| call.accept_incoming(cx))
-// .await
-// .unwrap();
-// let client_b_peer_id = client_b.peer_id().unwrap();
-// let project_b = client_b
-// .build_remote_project(initial_project.id, cx_b)
-// .await;
-
-// let replica_id_b = project_b.read_with(cx_b, |project, _| project.replica_id());
-
-// executor.run_until_parked();
-
-// project_a.read_with(cx_a, |project, _| {
-// let client_b_collaborator = project.collaborators().get(&client_b_peer_id).unwrap();
-// assert_eq!(client_b_collaborator.replica_id, replica_id_b);
-// });
-
-// project_b.read_with(cx_b, |project, cx| {
-// let worktree = project.worktrees().next().unwrap().read(cx);
-// assert_eq!(
-// worktree.paths().map(AsRef::as_ref).collect::<Vec<_>>(),
-// [
-// Path::new(".gitignore"),
-// Path::new("a.txt"),
-// Path::new("b.txt"),
-// Path::new("ignored-dir"),
-// ]
-// );
-// });
-
-// project_b
-// .update(cx_b, |project, cx| {
-// let worktree = project.worktrees().next().unwrap();
-// let entry = worktree.read(cx).entry_for_path("ignored-dir").unwrap();
-// project.expand_entry(worktree_id, entry.id, cx).unwrap()
-// })
-// .await
-// .unwrap();
-
-// project_b.read_with(cx_b, |project, cx| {
-// let worktree = project.worktrees().next().unwrap().read(cx);
-// assert_eq!(
-// worktree.paths().map(AsRef::as_ref).collect::<Vec<_>>(),
-// [
-// Path::new(".gitignore"),
-// Path::new("a.txt"),
-// Path::new("b.txt"),
-// Path::new("ignored-dir"),
-// Path::new("ignored-dir/c.txt"),
-// Path::new("ignored-dir/d.txt"),
-// ]
-// );
-// });
-
-// // Open the same file as client B and client A.
-// let buffer_b = project_b
-// .update(cx_b, |p, cx| p.open_buffer((worktree_id, "b.txt"), cx))
-// .await
-// .unwrap();
-
-// buffer_b.read_with(cx_b, |buf, _| assert_eq!(buf.text(), "b-contents"));
-
-// project_a.read_with(cx_a, |project, cx| {
-// assert!(project.has_open_buffer((worktree_id, "b.txt"), cx))
-// });
-// let buffer_a = project_a
-// .update(cx_a, |p, cx| p.open_buffer((worktree_id, "b.txt"), cx))
-// .await
-// .unwrap();
-
-// let editor_b = window_b.build_view(cx_b, |cx| Editor::for_buffer(buffer_b, None, cx));
-
-// // Client A sees client B's selection
-// executor.run_until_parked();
-
-// buffer_a.read_with(cx_a, |buffer, _| {
-// buffer
-// .snapshot()
-// .remote_selections_in_range(Anchor::MIN..Anchor::MAX)
-// .count()
-// == 1
-// });
-
-// // Edit the buffer as client B and see that edit as client A.
-// editor_b.update(cx_b, |editor, cx| editor.handle_input("ok, ", cx));
-// executor.run_until_parked();
-
-// buffer_a.read_with(cx_a, |buffer, _| {
-// assert_eq!(buffer.text(), "ok, b-contents")
-// });
-
-// // Client B can invite client C on a project shared by client A.
-// active_call_b
-// .update(cx_b, |call, cx| {
-// call.invite(client_c.user_id().unwrap(), Some(project_b.clone()), cx)
-// })
-// .await
-// .unwrap();
-
-// let incoming_call_c = active_call_c.read_with(cx_c, |call, _| call.incoming());
-// executor.run_until_parked();
-// let call = incoming_call_c.borrow().clone().unwrap();
-// assert_eq!(call.calling_user.github_login, "user_b");
-// let initial_project = call.initial_project.unwrap();
-// active_call_c
-// .update(cx_c, |call, cx| call.accept_incoming(cx))
-// .await
-// .unwrap();
-// let _project_c = client_c
-// .build_remote_project(initial_project.id, cx_c)
-// .await;
-
-// // Client B closes the editor, and client A sees client B's selections removed.
-// cx_b.update(move |_| drop(editor_b));
-// executor.run_until_parked();
-
-// buffer_a.read_with(cx_a, |buffer, _| {
-// buffer
-// .snapshot()
-// .remote_selections_in_range(Anchor::MIN..Anchor::MAX)
-// .count()
-// == 0
-// });
-// }
-
-// #[gpui::test(iterations = 10)]
-// async fn test_on_input_format_from_host_to_guest(
-// executor: BackgroundExecutor,
-// cx_a: &mut TestAppContext,
-// cx_b: &mut TestAppContext,
-// ) {
-// let mut server = TestServer::start(&executor).await;
-// let client_a = server.create_client(cx_a, "user_a").await;
-// let client_b = server.create_client(cx_b, "user_b").await;
-// server
-// .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
-// .await;
-// let active_call_a = cx_a.read(ActiveCall::global);
-
-// // Set up a fake language server.
-// let mut language = Language::new(
-// LanguageConfig {
-// name: "Rust".into(),
-// path_suffixes: vec!["rs".to_string()],
-// ..Default::default()
-// },
-// Some(tree_sitter_rust::language()),
-// );
-// let mut fake_language_servers = language
-// .set_fake_lsp_adapter(Arc::new(FakeLspAdapter {
-// capabilities: lsp::ServerCapabilities {
-// document_on_type_formatting_provider: Some(lsp::DocumentOnTypeFormattingOptions {
-// first_trigger_character: ":".to_string(),
-// more_trigger_character: Some(vec![">".to_string()]),
-// }),
-// ..Default::default()
-// },
-// ..Default::default()
-// }))
-// .await;
-// client_a.language_registry().add(Arc::new(language));
-
-// client_a
-// .fs()
-// .insert_tree(
-// "/a",
-// json!({
-// "main.rs": "fn main() { a }",
-// "other.rs": "// Test file",
-// }),
-// )
-// .await;
-// let (project_a, worktree_id) = client_a.build_local_project("/a", cx_a).await;
-// let project_id = active_call_a
-// .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
-// .await
-// .unwrap();
-// let project_b = client_b.build_remote_project(project_id, cx_b).await;
-
-// // Open a file in an editor as the host.
-// let buffer_a = project_a
-// .update(cx_a, |p, cx| p.open_buffer((worktree_id, "main.rs"), cx))
-// .await
-// .unwrap();
-// let window_a = cx_a.add_empty_window();
-// let editor_a = window_a
-// .update(cx_a, |_, cx| {
-// cx.build_view(|cx| Editor::for_buffer(buffer_a, Some(project_a.clone()), cx))
-// })
-// .unwrap();
-
-// let fake_language_server = fake_language_servers.next().await.unwrap();
-// executor.run_until_parked();
-
-// // Receive an OnTypeFormatting request as the host's language server.
-// // Return some formattings from the host's language server.
-// fake_language_server.handle_request::<lsp::request::OnTypeFormatting, _, _>(
-// |params, _| async move {
-// assert_eq!(
-// params.text_document_position.text_document.uri,
-// lsp::Url::from_file_path("/a/main.rs").unwrap(),
-// );
-// assert_eq!(
-// params.text_document_position.position,
-// lsp::Position::new(0, 14),
-// );
-
-// Ok(Some(vec![lsp::TextEdit {
-// new_text: "~<".to_string(),
-// range: lsp::Range::new(lsp::Position::new(0, 14), lsp::Position::new(0, 14)),
-// }]))
-// },
-// );
-
-// // Open the buffer on the guest and see that the formattings worked
-// let buffer_b = project_b
-// .update(cx_b, |p, cx| p.open_buffer((worktree_id, "main.rs"), cx))
-// .await
-// .unwrap();
-
-// // Type a on type formatting trigger character as the guest.
-// editor_a.update(cx_a, |editor, cx| {
-// cx.focus(&editor_a);
-// editor.change_selections(None, cx, |s| s.select_ranges([13..13]));
-// editor.handle_input(">", cx);
-// });
-
-// executor.run_until_parked();
-
-// buffer_b.read_with(cx_b, |buffer, _| {
-// assert_eq!(buffer.text(), "fn main() { a>~< }")
-// });
-
-// // Undo should remove LSP edits first
-// editor_a.update(cx_a, |editor, cx| {
-// assert_eq!(editor.text(cx), "fn main() { a>~< }");
-// editor.undo(&Undo, cx);
-// assert_eq!(editor.text(cx), "fn main() { a> }");
-// });
-// executor.run_until_parked();
-
-// buffer_b.read_with(cx_b, |buffer, _| {
-// assert_eq!(buffer.text(), "fn main() { a> }")
-// });
-
-// editor_a.update(cx_a, |editor, cx| {
-// assert_eq!(editor.text(cx), "fn main() { a> }");
-// editor.undo(&Undo, cx);
-// assert_eq!(editor.text(cx), "fn main() { a }");
-// });
-// executor.run_until_parked();
-
-// buffer_b.read_with(cx_b, |buffer, _| {
-// assert_eq!(buffer.text(), "fn main() { a }")
-// });
-// }
-
-// #[gpui::test(iterations = 10)]
-// async fn test_on_input_format_from_guest_to_host(
-// executor: BackgroundExecutor,
-// cx_a: &mut TestAppContext,
-// cx_b: &mut TestAppContext,
-// ) {
-// let mut server = TestServer::start(&executor).await;
-// let client_a = server.create_client(cx_a, "user_a").await;
-// let client_b = server.create_client(cx_b, "user_b").await;
-// server
-// .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
-// .await;
-// let active_call_a = cx_a.read(ActiveCall::global);
-
-// // Set up a fake language server.
-// let mut language = Language::new(
-// LanguageConfig {
-// name: "Rust".into(),
-// path_suffixes: vec!["rs".to_string()],
-// ..Default::default()
-// },
-// Some(tree_sitter_rust::language()),
-// );
-// let mut fake_language_servers = language
-// .set_fake_lsp_adapter(Arc::new(FakeLspAdapter {
-// capabilities: lsp::ServerCapabilities {
-// document_on_type_formatting_provider: Some(lsp::DocumentOnTypeFormattingOptions {
-// first_trigger_character: ":".to_string(),
-// more_trigger_character: Some(vec![">".to_string()]),
-// }),
-// ..Default::default()
-// },
-// ..Default::default()
-// }))
-// .await;
-// client_a.language_registry().add(Arc::new(language));
-
-// client_a
-// .fs()
-// .insert_tree(
-// "/a",
-// json!({
-// "main.rs": "fn main() { a }",
-// "other.rs": "// Test file",
-// }),
-// )
-// .await;
-// let (project_a, worktree_id) = client_a.build_local_project("/a", cx_a).await;
-// let project_id = active_call_a
-// .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
-// .await
-// .unwrap();
-// let project_b = client_b.build_remote_project(project_id, cx_b).await;
-
-// // Open a file in an editor as the guest.
-// let buffer_b = project_b
-// .update(cx_b, |p, cx| p.open_buffer((worktree_id, "main.rs"), cx))
-// .await
-// .unwrap();
-// let window_b = cx_b.add_empty_window();
-// let editor_b = window_b.build_view(cx_b, |cx| {
-// Editor::for_buffer(buffer_b, Some(project_b.clone()), cx)
-// });
-
-// let fake_language_server = fake_language_servers.next().await.unwrap();
-// executor.run_until_parked();
-// // Type a on type formatting trigger character as the guest.
-// editor_b.update(cx_b, |editor, cx| {
-// editor.change_selections(None, cx, |s| s.select_ranges([13..13]));
-// editor.handle_input(":", cx);
-// cx.focus(&editor_b);
-// });
-
-// // Receive an OnTypeFormatting request as the host's language server.
-// // Return some formattings from the host's language server.
-// cx_a.foreground().start_waiting();
-// fake_language_server
-// .handle_request::<lsp::request::OnTypeFormatting, _, _>(|params, _| async move {
-// assert_eq!(
-// params.text_document_position.text_document.uri,
-// lsp::Url::from_file_path("/a/main.rs").unwrap(),
-// );
-// assert_eq!(
-// params.text_document_position.position,
-// lsp::Position::new(0, 14),
-// );
-
-// Ok(Some(vec![lsp::TextEdit {
-// new_text: "~:".to_string(),
-// range: lsp::Range::new(lsp::Position::new(0, 14), lsp::Position::new(0, 14)),
-// }]))
-// })
-// .next()
-// .await
-// .unwrap();
-// cx_a.foreground().finish_waiting();
-
-// // Open the buffer on the host and see that the formattings worked
-// let buffer_a = project_a
-// .update(cx_a, |p, cx| p.open_buffer((worktree_id, "main.rs"), cx))
-// .await
-// .unwrap();
-// executor.run_until_parked();
-
-// buffer_a.read_with(cx_a, |buffer, _| {
-// assert_eq!(buffer.text(), "fn main() { a:~: }")
-// });
-
-// // Undo should remove LSP edits first
-// editor_b.update(cx_b, |editor, cx| {
-// assert_eq!(editor.text(cx), "fn main() { a:~: }");
-// editor.undo(&Undo, cx);
-// assert_eq!(editor.text(cx), "fn main() { a: }");
-// });
-// executor.run_until_parked();
-
-// buffer_a.read_with(cx_a, |buffer, _| {
-// assert_eq!(buffer.text(), "fn main() { a: }")
-// });
-
-// editor_b.update(cx_b, |editor, cx| {
-// assert_eq!(editor.text(cx), "fn main() { a: }");
-// editor.undo(&Undo, cx);
-// assert_eq!(editor.text(cx), "fn main() { a }");
-// });
-// executor.run_until_parked();
-
-// buffer_a.read_with(cx_a, |buffer, _| {
-// assert_eq!(buffer.text(), "fn main() { a }")
-// });
-// }
-
-// #[gpui::test(iterations = 10)]
-// async fn test_mutual_editor_inlay_hint_cache_update(
-// executor: BackgroundExecutor,
-// cx_a: &mut TestAppContext,
-// cx_b: &mut TestAppContext,
-// ) {
-// let mut server = TestServer::start(&executor).await;
-// let client_a = server.create_client(cx_a, "user_a").await;
-// let client_b = server.create_client(cx_b, "user_b").await;
-// server
-// .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
-// .await;
-// let active_call_a = cx_a.read(ActiveCall::global);
-// let active_call_b = cx_b.read(ActiveCall::global);
-
-// cx_a.update(editor::init);
-// cx_b.update(editor::init);
-
-// cx_a.update(|cx| {
-// cx.update_global(|store: &mut SettingsStore, cx| {
-// store.update_user_settings::<AllLanguageSettings>(cx, |settings| {
-// settings.defaults.inlay_hints = Some(InlayHintSettings {
-// enabled: true,
-// show_type_hints: true,
-// show_parameter_hints: false,
-// show_other_hints: true,
-// })
-// });
-// });
-// });
-// cx_b.update(|cx| {
-// cx.update_global(|store: &mut SettingsStore, cx| {
-// store.update_user_settings::<AllLanguageSettings>(cx, |settings| {
-// settings.defaults.inlay_hints = Some(InlayHintSettings {
-// enabled: true,
-// show_type_hints: true,
-// show_parameter_hints: false,
-// show_other_hints: true,
-// })
-// });
-// });
-// });
-
-// let mut language = Language::new(
-// LanguageConfig {
-// name: "Rust".into(),
-// path_suffixes: vec!["rs".to_string()],
-// ..Default::default()
-// },
-// Some(tree_sitter_rust::language()),
-// );
-// let mut fake_language_servers = language
-// .set_fake_lsp_adapter(Arc::new(FakeLspAdapter {
-// capabilities: lsp::ServerCapabilities {
-// inlay_hint_provider: Some(lsp::OneOf::Left(true)),
-// ..Default::default()
-// },
-// ..Default::default()
-// }))
-// .await;
-// let language = Arc::new(language);
-// client_a.language_registry().add(Arc::clone(&language));
-// client_b.language_registry().add(language);
-
-// // Client A opens a project.
-// client_a
-// .fs()
-// .insert_tree(
-// "/a",
-// json!({
-// "main.rs": "fn main() { a } // and some long comment to ensure inlay hints are not trimmed out",
-// "other.rs": "// Test file",
-// }),
-// )
-// .await;
-// let (project_a, worktree_id) = client_a.build_local_project("/a", cx_a).await;
-// active_call_a
-// .update(cx_a, |call, cx| call.set_location(Some(&project_a), cx))
-// .await
-// .unwrap();
-// let project_id = active_call_a
-// .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
-// .await
-// .unwrap();
-
-// // Client B joins the project
-// let project_b = client_b.build_remote_project(project_id, cx_b).await;
-// active_call_b
-// .update(cx_b, |call, cx| call.set_location(Some(&project_b), cx))
-// .await
-// .unwrap();
-
-// let workspace_a = client_a.build_workspace(&project_a, cx_a).root_view(cx_a);
-// cx_a.foreground().start_waiting();
-
-// // The host opens a rust file.
-// let _buffer_a = project_a
-// .update(cx_a, |project, cx| {
-// project.open_local_buffer("/a/main.rs", cx)
-// })
-// .await
-// .unwrap();
-// let fake_language_server = fake_language_servers.next().await.unwrap();
-// let editor_a = workspace_a
-// .update(cx_a, |workspace, cx| {
-// workspace.open_path((worktree_id, "main.rs"), None, true, cx)
-// })
-// .await
-// .unwrap()
-// .downcast::<Editor>()
-// .unwrap();
-
-// // Set up the language server to return an additional inlay hint on each request.
-// let edits_made = Arc::new(AtomicUsize::new(0));
-// let closure_edits_made = Arc::clone(&edits_made);
-// fake_language_server
-// .handle_request::<lsp::request::InlayHintRequest, _, _>(move |params, _| {
-// let task_edits_made = Arc::clone(&closure_edits_made);
-// async move {
-// assert_eq!(
-// params.text_document.uri,
-// lsp::Url::from_file_path("/a/main.rs").unwrap(),
-// );
-// let edits_made = task_edits_made.load(atomic::Ordering::Acquire);
-// Ok(Some(vec![lsp::InlayHint {
-// position: lsp::Position::new(0, edits_made as u32),
-// label: lsp::InlayHintLabel::String(edits_made.to_string()),
-// kind: None,
-// text_edits: None,
-// tooltip: None,
-// padding_left: None,
-// padding_right: None,
-// data: None,
-// }]))
-// }
-// })
-// .next()
-// .await
-// .unwrap();
-
-// executor.run_until_parked();
-
-// let initial_edit = edits_made.load(atomic::Ordering::Acquire);
-// editor_a.update(cx_a, |editor, _| {
-// assert_eq!(
-// vec![initial_edit.to_string()],
-// extract_hint_labels(editor),
-// "Host should get its first hints when opens an editor"
-// );
-// let inlay_cache = editor.inlay_hint_cache();
-// assert_eq!(
-// inlay_cache.version(),
-// 1,
-// "Host editor update the cache version after every cache/view change",
-// );
-// });
-// let workspace_b = client_b.build_workspace(&project_b, cx_b).root(cx_b);
-// let editor_b = workspace_b
-// .update(cx_b, |workspace, cx| {
-// workspace.open_path((worktree_id, "main.rs"), None, true, cx)
-// })
-// .await
-// .unwrap()
-// .downcast::<Editor>()
-// .unwrap();
-
-// executor.run_until_parked();
-// editor_b.update(cx_b, |editor, _| {
-// assert_eq!(
-// vec![initial_edit.to_string()],
-// extract_hint_labels(editor),
-// "Client should get its first hints when opens an editor"
-// );
-// let inlay_cache = editor.inlay_hint_cache();
-// assert_eq!(
-// inlay_cache.version(),
-// 1,
-// "Guest editor update the cache version after every cache/view change"
-// );
-// });
-
-// let after_client_edit = edits_made.fetch_add(1, atomic::Ordering::Release) + 1;
-// editor_b.update(cx_b, |editor, cx| {
-// editor.change_selections(None, cx, |s| s.select_ranges([13..13].clone()));
-// editor.handle_input(":", cx);
-// cx.focus(&editor_b);
-// });
-
-// executor.run_until_parked();
-// editor_a.update(cx_a, |editor, _| {
-// assert_eq!(
-// vec![after_client_edit.to_string()],
-// extract_hint_labels(editor),
-// );
-// let inlay_cache = editor.inlay_hint_cache();
-// assert_eq!(inlay_cache.version(), 2);
-// });
-// editor_b.update(cx_b, |editor, _| {
-// assert_eq!(
-// vec![after_client_edit.to_string()],
-// extract_hint_labels(editor),
-// );
-// let inlay_cache = editor.inlay_hint_cache();
-// assert_eq!(inlay_cache.version(), 2);
-// });
-
-// let after_host_edit = edits_made.fetch_add(1, atomic::Ordering::Release) + 1;
-// editor_a.update(cx_a, |editor, cx| {
-// editor.change_selections(None, cx, |s| s.select_ranges([13..13]));
-// editor.handle_input("a change to increment both buffers' versions", cx);
-// cx.focus(&editor_a);
-// });
-
-// executor.run_until_parked();
-// editor_a.update(cx_a, |editor, _| {
-// assert_eq!(
-// vec![after_host_edit.to_string()],
-// extract_hint_labels(editor),
-// );
-// let inlay_cache = editor.inlay_hint_cache();
-// assert_eq!(inlay_cache.version(), 3);
-// });
-// editor_b.update(cx_b, |editor, _| {
-// assert_eq!(
-// vec![after_host_edit.to_string()],
-// extract_hint_labels(editor),
-// );
-// let inlay_cache = editor.inlay_hint_cache();
-// assert_eq!(inlay_cache.version(), 3);
-// });
-
-// let after_special_edit_for_refresh = edits_made.fetch_add(1, atomic::Ordering::Release) + 1;
-// fake_language_server
-// .request::<lsp::request::InlayHintRefreshRequest>(())
-// .await
-// .expect("inlay refresh request failed");
-
-// executor.run_until_parked();
-// editor_a.update(cx_a, |editor, _| {
-// assert_eq!(
-// vec![after_special_edit_for_refresh.to_string()],
-// extract_hint_labels(editor),
-// "Host should react to /refresh LSP request"
-// );
-// let inlay_cache = editor.inlay_hint_cache();
-// assert_eq!(
-// inlay_cache.version(),
-// 4,
-// "Host should accepted all edits and bump its cache version every time"
-// );
-// });
-// editor_b.update(cx_b, |editor, _| {
-// assert_eq!(
-// vec![after_special_edit_for_refresh.to_string()],
-// extract_hint_labels(editor),
-// "Guest should get a /refresh LSP request propagated by host"
-// );
-// let inlay_cache = editor.inlay_hint_cache();
-// assert_eq!(
-// inlay_cache.version(),
-// 4,
-// "Guest should accepted all edits and bump its cache version every time"
-// );
-// });
-// }
-
-// #[gpui::test(iterations = 10)]
-// async fn test_inlay_hint_refresh_is_forwarded(
-// executor: BackgroundExecutor,
-// cx_a: &mut TestAppContext,
-// cx_b: &mut TestAppContext,
-// ) {
-// let mut server = TestServer::start(&executor).await;
-// let client_a = server.create_client(cx_a, "user_a").await;
-// let client_b = server.create_client(cx_b, "user_b").await;
-// server
-// .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
-// .await;
-// let active_call_a = cx_a.read(ActiveCall::global);
-// let active_call_b = cx_b.read(ActiveCall::global);
-
-// cx_a.update(editor::init);
-// cx_b.update(editor::init);
-
-// cx_a.update(|cx| {
-// cx.update_global(|store: &mut SettingsStore, cx| {
-// store.update_user_settings::<AllLanguageSettings>(cx, |settings| {
-// settings.defaults.inlay_hints = Some(InlayHintSettings {
-// enabled: false,
-// show_type_hints: false,
-// show_parameter_hints: false,
-// show_other_hints: false,
-// })
-// });
-// });
-// });
-// cx_b.update(|cx| {
-// cx.update_global(|store: &mut SettingsStore, cx| {
-// store.update_user_settings::<AllLanguageSettings>(cx, |settings| {
-// settings.defaults.inlay_hints = Some(InlayHintSettings {
-// enabled: true,
-// show_type_hints: true,
-// show_parameter_hints: true,
-// show_other_hints: true,
-// })
-// });
-// });
-// });
-
-// let mut language = Language::new(
-// LanguageConfig {
-// name: "Rust".into(),
-// path_suffixes: vec!["rs".to_string()],
-// ..Default::default()
-// },
-// Some(tree_sitter_rust::language()),
-// );
-// let mut fake_language_servers = language
-// .set_fake_lsp_adapter(Arc::new(FakeLspAdapter {
-// capabilities: lsp::ServerCapabilities {
-// inlay_hint_provider: Some(lsp::OneOf::Left(true)),
-// ..Default::default()
-// },
-// ..Default::default()
-// }))
-// .await;
-// let language = Arc::new(language);
-// client_a.language_registry().add(Arc::clone(&language));
-// client_b.language_registry().add(language);
-
-// client_a
-// .fs()
-// .insert_tree(
-// "/a",
-// json!({
-// "main.rs": "fn main() { a } // and some long comment to ensure inlay hints are not trimmed out",
-// "other.rs": "// Test file",
-// }),
-// )
-// .await;
-// let (project_a, worktree_id) = client_a.build_local_project("/a", cx_a).await;
-// active_call_a
-// .update(cx_a, |call, cx| call.set_location(Some(&project_a), cx))
-// .await
-// .unwrap();
-// let project_id = active_call_a
-// .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
-// .await
-// .unwrap();
-
-// let project_b = client_b.build_remote_project(project_id, cx_b).await;
-// active_call_b
-// .update(cx_b, |call, cx| call.set_location(Some(&project_b), cx))
-// .await
-// .unwrap();
-
-// let workspace_a = client_a.build_workspace(&project_a, cx_a).root(cx_a);
-// let workspace_b = client_b.build_workspace(&project_b, cx_b).root(cx_b);
-// cx_a.foreground().start_waiting();
-// cx_b.foreground().start_waiting();
-
-// let editor_a = workspace_a
-// .update(cx_a, |workspace, cx| {
-// workspace.open_path((worktree_id, "main.rs"), None, true, cx)
-// })
-// .await
-// .unwrap()
-// .downcast::<Editor>()
-// .unwrap();
-
-// let editor_b = workspace_b
-// .update(cx_b, |workspace, cx| {
-// workspace.open_path((worktree_id, "main.rs"), None, true, cx)
-// })
-// .await
-// .unwrap()
-// .downcast::<Editor>()
-// .unwrap();
-
-// let other_hints = Arc::new(AtomicBool::new(false));
-// let fake_language_server = fake_language_servers.next().await.unwrap();
-// let closure_other_hints = Arc::clone(&other_hints);
-// fake_language_server
-// .handle_request::<lsp::request::InlayHintRequest, _, _>(move |params, _| {
-// let task_other_hints = Arc::clone(&closure_other_hints);
-// async move {
-// assert_eq!(
-// params.text_document.uri,
-// lsp::Url::from_file_path("/a/main.rs").unwrap(),
-// );
-// let other_hints = task_other_hints.load(atomic::Ordering::Acquire);
-// let character = if other_hints { 0 } else { 2 };
-// let label = if other_hints {
-// "other hint"
-// } else {
-// "initial hint"
-// };
-// Ok(Some(vec![lsp::InlayHint {
-// position: lsp::Position::new(0, character),
-// label: lsp::InlayHintLabel::String(label.to_string()),
-// kind: None,
-// text_edits: None,
-// tooltip: None,
-// padding_left: None,
-// padding_right: None,
-// data: None,
-// }]))
-// }
-// })
-// .next()
-// .await
-// .unwrap();
-// cx_a.foreground().finish_waiting();
-// cx_b.foreground().finish_waiting();
-
-// executor.run_until_parked();
-// editor_a.update(cx_a, |editor, _| {
-// assert!(
-// extract_hint_labels(editor).is_empty(),
-// "Host should get no hints due to them turned off"
-// );
-// let inlay_cache = editor.inlay_hint_cache();
-// assert_eq!(
-// inlay_cache.version(),
-// 0,
-// "Turned off hints should not generate version updates"
-// );
-// });
-
-// executor.run_until_parked();
-// editor_b.update(cx_b, |editor, _| {
-// assert_eq!(
-// vec!["initial hint".to_string()],
-// extract_hint_labels(editor),
-// "Client should get its first hints when opens an editor"
-// );
-// let inlay_cache = editor.inlay_hint_cache();
-// assert_eq!(
-// inlay_cache.version(),
-// 1,
-// "Should update cache verison after first hints"
-// );
-// });
-
-// other_hints.fetch_or(true, atomic::Ordering::Release);
-// fake_language_server
-// .request::<lsp::request::InlayHintRefreshRequest>(())
-// .await
-// .expect("inlay refresh request failed");
-// executor.run_until_parked();
-// editor_a.update(cx_a, |editor, _| {
-// assert!(
-// extract_hint_labels(editor).is_empty(),
-// "Host should get nop hints due to them turned off, even after the /refresh"
-// );
-// let inlay_cache = editor.inlay_hint_cache();
-// assert_eq!(
-// inlay_cache.version(),
-// 0,
-// "Turned off hints should not generate version updates, again"
-// );
-// });
-
-// executor.run_until_parked();
-// editor_b.update(cx_b, |editor, _| {
-// assert_eq!(
-// vec!["other hint".to_string()],
-// extract_hint_labels(editor),
-// "Guest should get a /refresh LSP request propagated by host despite host hints are off"
-// );
-// let inlay_cache = editor.inlay_hint_cache();
-// assert_eq!(
-// inlay_cache.version(),
-// 2,
-// "Guest should accepted all edits and bump its cache version every time"
-// );
-// });
-// }
-
-// fn extract_hint_labels(editor: &Editor) -> Vec<String> {
-// let mut labels = Vec::new();
-// for hint in editor.inlay_hint_cache().hints() {
-// match hint.label {
-// project::InlayHintLabel::String(s) => labels.push(s),
-// _ => unreachable!(),
-// }
-// }
-// labels
-// }
+use std::{
+ path::Path,
+ sync::{
+ atomic::{self, AtomicBool, AtomicUsize},
+ Arc,
+ },
+};
+
+use call::ActiveCall;
+use editor::{
+ test::editor_test_context::{AssertionContextManager, EditorTestContext},
+ ConfirmCodeAction, ConfirmCompletion, ConfirmRename, Editor, Redo, Rename, ToggleCodeActions,
+ Undo,
+};
+use futures::StreamExt;
+use gpui::{TestAppContext, VisualContext, VisualTestContext};
+use indoc::indoc;
+use language::{
+ language_settings::{AllLanguageSettings, InlayHintSettings},
+ tree_sitter_rust, FakeLspAdapter, Language, LanguageConfig,
+};
+use rpc::RECEIVE_TIMEOUT;
+use serde_json::json;
+use settings::SettingsStore;
+use text::Point;
+use workspace::Workspace;
+
+use crate::{rpc::RECONNECT_TIMEOUT, tests::TestServer};
+
+#[gpui::test(iterations = 10)]
+async fn test_host_disconnect(
+ cx_a: &mut TestAppContext,
+ cx_b: &mut TestAppContext,
+ cx_c: &mut TestAppContext,
+) {
+ let mut server = TestServer::start(cx_a.executor()).await;
+ let client_a = server.create_client(cx_a, "user_a").await;
+ let client_b = server.create_client(cx_b, "user_b").await;
+ let client_c = server.create_client(cx_c, "user_c").await;
+ server
+ .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b), (&client_c, cx_c)])
+ .await;
+
+ cx_b.update(editor::init);
+
+ client_a
+ .fs()
+ .insert_tree(
+ "/a",
+ serde_json::json!({
+ "a.txt": "a-contents",
+ "b.txt": "b-contents",
+ }),
+ )
+ .await;
+
+ let active_call_a = cx_a.read(ActiveCall::global);
+ let (project_a, worktree_id) = client_a.build_local_project("/a", cx_a).await;
+
+ let worktree_a = project_a.read_with(cx_a, |project, _| project.worktrees().next().unwrap());
+ let project_id = active_call_a
+ .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
+ .await
+ .unwrap();
+
+ let project_b = client_b.build_remote_project(project_id, cx_b).await;
+ cx_a.background_executor.run_until_parked();
+
+ assert!(worktree_a.read_with(cx_a, |tree, _| tree.as_local().unwrap().is_shared()));
+
+ let workspace_b =
+ cx_b.add_window(|cx| Workspace::new(0, project_b.clone(), client_b.app_state.clone(), cx));
+ let cx_b = &mut VisualTestContext::from_window(*workspace_b, cx_b);
+
+ let editor_b = workspace_b
+ .update(cx_b, |workspace, cx| {
+ workspace.open_path((worktree_id, "b.txt"), None, true, cx)
+ })
+ .unwrap()
+ .await
+ .unwrap()
+ .downcast::<Editor>()
+ .unwrap();
+
+ //TODO: focus
+ assert!(cx_b.update_view(&editor_b, |editor, cx| editor.is_focused(cx)));
+ editor_b.update(cx_b, |editor, cx| editor.insert("X", cx));
+ //todo(is_edited)
+ // assert!(workspace_b.is_edited(cx_b));
+
+ // Drop client A's connection. Collaborators should disappear and the project should not be shown as shared.
+ server.forbid_connections();
+ server.disconnect_client(client_a.peer_id().unwrap());
+ cx_a.background_executor
+ .advance_clock(RECEIVE_TIMEOUT + RECONNECT_TIMEOUT);
+
+ project_a.read_with(cx_a, |project, _| project.collaborators().is_empty());
+
+ project_a.read_with(cx_a, |project, _| assert!(!project.is_shared()));
+
+ project_b.read_with(cx_b, |project, _| project.is_read_only());
+
+ assert!(worktree_a.read_with(cx_a, |tree, _| !tree.as_local().unwrap().is_shared()));
+
+ // Ensure client B's edited state is reset and that the whole window is blurred.
+
+ workspace_b
+ .update(cx_b, |_, cx| {
+ assert_eq!(cx.focused(), None);
+ })
+ .unwrap();
+ // assert!(!workspace_b.is_edited(cx_b));
+
+ // Ensure client B is not prompted to save edits when closing window after disconnecting.
+ let can_close = workspace_b
+ .update(cx_b, |workspace, cx| workspace.prepare_to_close(true, cx))
+ .unwrap()
+ .await
+ .unwrap();
+ assert!(can_close);
+
+ // Allow client A to reconnect to the server.
+ server.allow_connections();
+ cx_a.background_executor.advance_clock(RECEIVE_TIMEOUT);
+
+ // Client B calls client A again after they reconnected.
+ let active_call_b = cx_b.read(ActiveCall::global);
+ active_call_b
+ .update(cx_b, |call, cx| {
+ call.invite(client_a.user_id().unwrap(), None, cx)
+ })
+ .await
+ .unwrap();
+ cx_a.background_executor.run_until_parked();
+ active_call_a
+ .update(cx_a, |call, cx| call.accept_incoming(cx))
+ .await
+ .unwrap();
+
+ active_call_a
+ .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
+ .await
+ .unwrap();
+
+ // Drop client A's connection again. We should still unshare it successfully.
+ server.forbid_connections();
+ server.disconnect_client(client_a.peer_id().unwrap());
+ cx_a.background_executor
+ .advance_clock(RECEIVE_TIMEOUT + RECONNECT_TIMEOUT);
+
+ project_a.read_with(cx_a, |project, _| assert!(!project.is_shared()));
+}
+
+#[gpui::test]
+async fn test_newline_above_or_below_does_not_move_guest_cursor(
+ cx_a: &mut TestAppContext,
+ cx_b: &mut TestAppContext,
+) {
+ let mut server = TestServer::start(cx_a.executor()).await;
+ let client_a = server.create_client(cx_a, "user_a").await;
+ let client_b = server.create_client(cx_b, "user_b").await;
+ let executor = cx_a.executor();
+ server
+ .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
+ .await;
+ let active_call_a = cx_a.read(ActiveCall::global);
+
+ client_a
+ .fs()
+ .insert_tree("/dir", json!({ "a.txt": "Some text\n" }))
+ .await;
+ let (project_a, worktree_id) = client_a.build_local_project("/dir", cx_a).await;
+ let project_id = active_call_a
+ .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
+ .await
+ .unwrap();
+
+ let project_b = client_b.build_remote_project(project_id, cx_b).await;
+
+ // Open a buffer as client A
+ let buffer_a = project_a
+ .update(cx_a, |p, cx| p.open_buffer((worktree_id, "a.txt"), cx))
+ .await
+ .unwrap();
+ let window_a = cx_a.add_empty_window();
+ let editor_a =
+ window_a.build_view(cx_a, |cx| Editor::for_buffer(buffer_a, Some(project_a), cx));
+
+ let mut editor_cx_a = EditorTestContext {
+ cx: VisualTestContext::from_window(window_a, cx_a),
+ window: window_a.into(),
+ editor: editor_a,
+ assertion_cx: AssertionContextManager::new(),
+ };
+
+ let window_b = cx_b.add_empty_window();
+ let mut cx_b = VisualTestContext::from_window(window_b, cx_b);
+
+ // Open a buffer as client B
+ let buffer_b = project_b
+ .update(&mut cx_b, |p, cx| p.open_buffer((worktree_id, "a.txt"), cx))
+ .await
+ .unwrap();
+ let editor_b = window_b.build_view(&mut cx_b, |cx| {
+ Editor::for_buffer(buffer_b, Some(project_b), cx)
+ });
+ let mut editor_cx_b = EditorTestContext {
+ cx: cx_b,
+ window: window_b.into(),
+ editor: editor_b,
+ assertion_cx: AssertionContextManager::new(),
+ };
+
+ // Test newline above
+ editor_cx_a.set_selections_state(indoc! {"
+ Some textˇ
+ "});
+ editor_cx_b.set_selections_state(indoc! {"
+ Some textˇ
+ "});
+ editor_cx_a.update_editor(|editor, cx| editor.newline_above(&editor::NewlineAbove, cx));
+ executor.run_until_parked();
+ editor_cx_a.assert_editor_state(indoc! {"
+ ˇ
+ Some text
+ "});
+ editor_cx_b.assert_editor_state(indoc! {"
+
+ Some textˇ
+ "});
+
+ // Test newline below
+ editor_cx_a.set_selections_state(indoc! {"
+
+ Some textˇ
+ "});
+ editor_cx_b.set_selections_state(indoc! {"
+
+ Some textˇ
+ "});
+ editor_cx_a.update_editor(|editor, cx| editor.newline_below(&editor::NewlineBelow, cx));
+ executor.run_until_parked();
+ editor_cx_a.assert_editor_state(indoc! {"
+
+ Some text
+ ˇ
+ "});
+ editor_cx_b.assert_editor_state(indoc! {"
+
+ Some textˇ
+
+ "});
+}
+
+#[gpui::test(iterations = 10)]
+async fn test_collaborating_with_completion(cx_a: &mut TestAppContext, cx_b: &mut TestAppContext) {
+ let mut server = TestServer::start(cx_a.executor()).await;
+ let client_a = server.create_client(cx_a, "user_a").await;
+ let client_b = server.create_client(cx_b, "user_b").await;
+ server
+ .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
+ .await;
+ let active_call_a = cx_a.read(ActiveCall::global);
+
+ // Set up a fake language server.
+ let mut language = Language::new(
+ LanguageConfig {
+ name: "Rust".into(),
+ path_suffixes: vec!["rs".to_string()],
+ ..Default::default()
+ },
+ Some(tree_sitter_rust::language()),
+ );
+ let mut fake_language_servers = language
+ .set_fake_lsp_adapter(Arc::new(FakeLspAdapter {
+ capabilities: lsp::ServerCapabilities {
+ completion_provider: Some(lsp::CompletionOptions {
+ trigger_characters: Some(vec![".".to_string()]),
+ resolve_provider: Some(true),
+ ..Default::default()
+ }),
+ ..Default::default()
+ },
+ ..Default::default()
+ }))
+ .await;
+ client_a.language_registry().add(Arc::new(language));
+
+ client_a
+ .fs()
+ .insert_tree(
+ "/a",
+ json!({
+ "main.rs": "fn main() { a }",
+ "other.rs": "",
+ }),
+ )
+ .await;
+ let (project_a, worktree_id) = client_a.build_local_project("/a", cx_a).await;
+ let project_id = active_call_a
+ .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
+ .await
+ .unwrap();
+ let project_b = client_b.build_remote_project(project_id, cx_b).await;
+
+ // Open a file in an editor as the guest.
+ let buffer_b = project_b
+ .update(cx_b, |p, cx| p.open_buffer((worktree_id, "main.rs"), cx))
+ .await
+ .unwrap();
+ let window_b = cx_b.add_empty_window();
+ let editor_b = window_b.build_view(cx_b, |cx| {
+ Editor::for_buffer(buffer_b.clone(), Some(project_b.clone()), cx)
+ });
+
+ let fake_language_server = fake_language_servers.next().await.unwrap();
+ cx_a.background_executor.run_until_parked();
+
+ buffer_b.read_with(cx_b, |buffer, _| {
+ assert!(!buffer.completion_triggers().is_empty())
+ });
+
+ let mut cx_b = VisualTestContext::from_window(window_b, cx_b);
+
+ // Type a completion trigger character as the guest.
+ editor_b.update(&mut cx_b, |editor, cx| {
+ editor.change_selections(None, cx, |s| s.select_ranges([13..13]));
+ editor.handle_input(".", cx);
+ });
+ cx_b.focus_view(&editor_b);
+
+ // Receive a completion request as the host's language server.
+ // Return some completions from the host's language server.
+ cx_a.executor().start_waiting();
+ fake_language_server
+ .handle_request::<lsp::request::Completion, _, _>(|params, _| async move {
+ assert_eq!(
+ params.text_document_position.text_document.uri,
+ lsp::Url::from_file_path("/a/main.rs").unwrap(),
+ );
+ assert_eq!(
+ params.text_document_position.position,
+ lsp::Position::new(0, 14),
+ );
+
+ Ok(Some(lsp::CompletionResponse::Array(vec![
+ lsp::CompletionItem {
+ label: "first_method(…)".into(),
+ detail: Some("fn(&mut self, B) -> C".into()),
+ text_edit: Some(lsp::CompletionTextEdit::Edit(lsp::TextEdit {
+ new_text: "first_method($1)".to_string(),
+ range: lsp::Range::new(
+ lsp::Position::new(0, 14),
+ lsp::Position::new(0, 14),
+ ),
+ })),
+ insert_text_format: Some(lsp::InsertTextFormat::SNIPPET),
+ ..Default::default()
+ },
+ lsp::CompletionItem {
+ label: "second_method(…)".into(),
+ detail: Some("fn(&mut self, C) -> D<E>".into()),
+ text_edit: Some(lsp::CompletionTextEdit::Edit(lsp::TextEdit {
+ new_text: "second_method()".to_string(),
+ range: lsp::Range::new(
+ lsp::Position::new(0, 14),
+ lsp::Position::new(0, 14),
+ ),
+ })),
+ insert_text_format: Some(lsp::InsertTextFormat::SNIPPET),
+ ..Default::default()
+ },
+ ])))
+ })
+ .next()
+ .await
+ .unwrap();
+ cx_a.executor().finish_waiting();
+
+ // Open the buffer on the host.
+ let buffer_a = project_a
+ .update(cx_a, |p, cx| p.open_buffer((worktree_id, "main.rs"), cx))
+ .await
+ .unwrap();
+ cx_a.executor().run_until_parked();
+
+ buffer_a.read_with(cx_a, |buffer, _| {
+ assert_eq!(buffer.text(), "fn main() { a. }")
+ });
+
+ // Confirm a completion on the guest.
+
+ editor_b.update(&mut cx_b, |editor, cx| {
+ assert!(editor.context_menu_visible());
+ editor.confirm_completion(&ConfirmCompletion { item_ix: Some(0) }, cx);
+ assert_eq!(editor.text(cx), "fn main() { a.first_method() }");
+ });
+
+ // Return a resolved completion from the host's language server.
+ // The resolved completion has an additional text edit.
+ fake_language_server.handle_request::<lsp::request::ResolveCompletionItem, _, _>(
+ |params, _| async move {
+ assert_eq!(params.label, "first_method(…)");
+ Ok(lsp::CompletionItem {
+ label: "first_method(…)".into(),
+ detail: Some("fn(&mut self, B) -> C".into()),
+ text_edit: Some(lsp::CompletionTextEdit::Edit(lsp::TextEdit {
+ new_text: "first_method($1)".to_string(),
+ range: lsp::Range::new(lsp::Position::new(0, 14), lsp::Position::new(0, 14)),
+ })),
+ additional_text_edits: Some(vec![lsp::TextEdit {
+ new_text: "use d::SomeTrait;\n".to_string(),
+ range: lsp::Range::new(lsp::Position::new(0, 0), lsp::Position::new(0, 0)),
+ }]),
+ insert_text_format: Some(lsp::InsertTextFormat::SNIPPET),
+ ..Default::default()
+ })
+ },
+ );
+
+ // The additional edit is applied.
+ cx_a.executor().run_until_parked();
+
+ buffer_a.read_with(cx_a, |buffer, _| {
+ assert_eq!(
+ buffer.text(),
+ "use d::SomeTrait;\nfn main() { a.first_method() }"
+ );
+ });
+
+ buffer_b.read_with(&mut cx_b, |buffer, _| {
+ assert_eq!(
+ buffer.text(),
+ "use d::SomeTrait;\nfn main() { a.first_method() }"
+ );
+ });
+}
+
+#[gpui::test(iterations = 10)]
+async fn test_collaborating_with_code_actions(
+ cx_a: &mut TestAppContext,
+ cx_b: &mut TestAppContext,
+) {
+ let mut server = TestServer::start(cx_a.executor()).await;
+ let client_a = server.create_client(cx_a, "user_a").await;
+ //
+ let client_b = server.create_client(cx_b, "user_b").await;
+ server
+ .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
+ .await;
+ let active_call_a = cx_a.read(ActiveCall::global);
+
+ cx_b.update(editor::init);
+
+ // Set up a fake language server.
+ let mut language = Language::new(
+ LanguageConfig {
+ name: "Rust".into(),
+ path_suffixes: vec!["rs".to_string()],
+ ..Default::default()
+ },
+ Some(tree_sitter_rust::language()),
+ );
+ let mut fake_language_servers = language.set_fake_lsp_adapter(Default::default()).await;
+ client_a.language_registry().add(Arc::new(language));
+
+ client_a
+ .fs()
+ .insert_tree(
+ "/a",
+ json!({
+ "main.rs": "mod other;\nfn main() { let foo = other::foo(); }",
+ "other.rs": "pub fn foo() -> usize { 4 }",
+ }),
+ )
+ .await;
+ let (project_a, worktree_id) = client_a.build_local_project("/a", cx_a).await;
+ let project_id = active_call_a
+ .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
+ .await
+ .unwrap();
+
+ // Join the project as client B.
+ let project_b = client_b.build_remote_project(project_id, cx_b).await;
+ let (workspace_b, cx_b) = client_b.build_workspace(&project_b, cx_b);
+ let editor_b = workspace_b
+ .update(cx_b, |workspace, cx| {
+ workspace.open_path((worktree_id, "main.rs"), None, true, cx)
+ })
+ .await
+ .unwrap()
+ .downcast::<Editor>()
+ .unwrap();
+
+ let mut fake_language_server = fake_language_servers.next().await.unwrap();
+ let mut requests = fake_language_server
+ .handle_request::<lsp::request::CodeActionRequest, _, _>(|params, _| async move {
+ assert_eq!(
+ params.text_document.uri,
+ lsp::Url::from_file_path("/a/main.rs").unwrap(),
+ );
+ assert_eq!(params.range.start, lsp::Position::new(0, 0));
+ assert_eq!(params.range.end, lsp::Position::new(0, 0));
+ Ok(None)
+ });
+ cx_a.background_executor
+ .advance_clock(editor::CODE_ACTIONS_DEBOUNCE_TIMEOUT * 2);
+ requests.next().await;
+
+ // Move cursor to a location that contains code actions.
+ editor_b.update(cx_b, |editor, cx| {
+ editor.change_selections(None, cx, |s| {
+ s.select_ranges([Point::new(1, 31)..Point::new(1, 31)])
+ });
+ });
+ cx_b.focus_view(&editor_b);
+
+ let mut requests = fake_language_server
+ .handle_request::<lsp::request::CodeActionRequest, _, _>(|params, _| async move {
+ assert_eq!(
+ params.text_document.uri,
+ lsp::Url::from_file_path("/a/main.rs").unwrap(),
+ );
+ assert_eq!(params.range.start, lsp::Position::new(1, 31));
+ assert_eq!(params.range.end, lsp::Position::new(1, 31));
+
+ Ok(Some(vec![lsp::CodeActionOrCommand::CodeAction(
+ lsp::CodeAction {
+ title: "Inline into all callers".to_string(),
+ edit: Some(lsp::WorkspaceEdit {
+ changes: Some(
+ [
+ (
+ lsp::Url::from_file_path("/a/main.rs").unwrap(),
+ vec![lsp::TextEdit::new(
+ lsp::Range::new(
+ lsp::Position::new(1, 22),
+ lsp::Position::new(1, 34),
+ ),
+ "4".to_string(),
+ )],
+ ),
+ (
+ lsp::Url::from_file_path("/a/other.rs").unwrap(),
+ vec![lsp::TextEdit::new(
+ lsp::Range::new(
+ lsp::Position::new(0, 0),
+ lsp::Position::new(0, 27),
+ ),
+ "".to_string(),
+ )],
+ ),
+ ]
+ .into_iter()
+ .collect(),
+ ),
+ ..Default::default()
+ }),
+ data: Some(json!({
+ "codeActionParams": {
+ "range": {
+ "start": {"line": 1, "column": 31},
+ "end": {"line": 1, "column": 31},
+ }
+ }
+ })),
+ ..Default::default()
+ },
+ )]))
+ });
+ cx_a.background_executor
+ .advance_clock(editor::CODE_ACTIONS_DEBOUNCE_TIMEOUT * 2);
+ requests.next().await;
+
+ // Toggle code actions and wait for them to display.
+ editor_b.update(cx_b, |editor, cx| {
+ editor.toggle_code_actions(
+ &ToggleCodeActions {
+ deployed_from_indicator: false,
+ },
+ cx,
+ );
+ });
+ cx_a.background_executor.run_until_parked();
+
+ editor_b.update(cx_b, |editor, _| assert!(editor.context_menu_visible()));
+
+ fake_language_server.remove_request_handler::<lsp::request::CodeActionRequest>();
+
+ // Confirming the code action will trigger a resolve request.
+ let confirm_action = editor_b
+ .update(cx_b, |editor, cx| {
+ Editor::confirm_code_action(editor, &ConfirmCodeAction { item_ix: Some(0) }, cx)
+ })
+ .unwrap();
+ fake_language_server.handle_request::<lsp::request::CodeActionResolveRequest, _, _>(
+ |_, _| async move {
+ Ok(lsp::CodeAction {
+ title: "Inline into all callers".to_string(),
+ edit: Some(lsp::WorkspaceEdit {
+ changes: Some(
+ [
+ (
+ lsp::Url::from_file_path("/a/main.rs").unwrap(),
+ vec![lsp::TextEdit::new(
+ lsp::Range::new(
+ lsp::Position::new(1, 22),
+ lsp::Position::new(1, 34),
+ ),
+ "4".to_string(),
+ )],
+ ),
+ (
+ lsp::Url::from_file_path("/a/other.rs").unwrap(),
+ vec![lsp::TextEdit::new(
+ lsp::Range::new(
+ lsp::Position::new(0, 0),
+ lsp::Position::new(0, 27),
+ ),
+ "".to_string(),
+ )],
+ ),
+ ]
+ .into_iter()
+ .collect(),
+ ),
+ ..Default::default()
+ }),
+ ..Default::default()
+ })
+ },
+ );
+
+ // After the action is confirmed, an editor containing both modified files is opened.
+ confirm_action.await.unwrap();
+
+ let code_action_editor = workspace_b.update(cx_b, |workspace, cx| {
+ workspace
+ .active_item(cx)
+ .unwrap()
+ .downcast::<Editor>()
+ .unwrap()
+ });
+ code_action_editor.update(cx_b, |editor, cx| {
+ assert_eq!(editor.text(cx), "mod other;\nfn main() { let foo = 4; }\n");
+ editor.undo(&Undo, cx);
+ assert_eq!(
+ editor.text(cx),
+ "mod other;\nfn main() { let foo = other::foo(); }\npub fn foo() -> usize { 4 }"
+ );
+ editor.redo(&Redo, cx);
+ assert_eq!(editor.text(cx), "mod other;\nfn main() { let foo = 4; }\n");
+ });
+}
+
+#[gpui::test(iterations = 10)]
+async fn test_collaborating_with_renames(cx_a: &mut TestAppContext, cx_b: &mut TestAppContext) {
+ let mut server = TestServer::start(cx_a.executor()).await;
+ let client_a = server.create_client(cx_a, "user_a").await;
+ let client_b = server.create_client(cx_b, "user_b").await;
+ server
+ .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
+ .await;
+ let active_call_a = cx_a.read(ActiveCall::global);
+
+ cx_b.update(editor::init);
+
+ // Set up a fake language server.
+ let mut language = Language::new(
+ LanguageConfig {
+ name: "Rust".into(),
+ path_suffixes: vec!["rs".to_string()],
+ ..Default::default()
+ },
+ Some(tree_sitter_rust::language()),
+ );
+ let mut fake_language_servers = language
+ .set_fake_lsp_adapter(Arc::new(FakeLspAdapter {
+ capabilities: lsp::ServerCapabilities {
+ rename_provider: Some(lsp::OneOf::Right(lsp::RenameOptions {
+ prepare_provider: Some(true),
+ work_done_progress_options: Default::default(),
+ })),
+ ..Default::default()
+ },
+ ..Default::default()
+ }))
+ .await;
+ client_a.language_registry().add(Arc::new(language));
+
+ client_a
+ .fs()
+ .insert_tree(
+ "/dir",
+ json!({
+ "one.rs": "const ONE: usize = 1;",
+ "two.rs": "const TWO: usize = one::ONE + one::ONE;"
+ }),
+ )
+ .await;
+ let (project_a, worktree_id) = client_a.build_local_project("/dir", cx_a).await;
+ let project_id = active_call_a
+ .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
+ .await
+ .unwrap();
+ let project_b = client_b.build_remote_project(project_id, cx_b).await;
+
+ let (workspace_b, cx_b) = client_b.build_workspace(&project_b, cx_b);
+ let editor_b = workspace_b
+ .update(cx_b, |workspace, cx| {
+ workspace.open_path((worktree_id, "one.rs"), None, true, cx)
+ })
+ .await
+ .unwrap()
+ .downcast::<Editor>()
+ .unwrap();
+ let fake_language_server = fake_language_servers.next().await.unwrap();
+
+ // Move cursor to a location that can be renamed.
+ let prepare_rename = editor_b.update(cx_b, |editor, cx| {
+ editor.change_selections(None, cx, |s| s.select_ranges([7..7]));
+ editor.rename(&Rename, cx).unwrap()
+ });
+
+ fake_language_server
+ .handle_request::<lsp::request::PrepareRenameRequest, _, _>(|params, _| async move {
+ assert_eq!(params.text_document.uri.as_str(), "file:///dir/one.rs");
+ assert_eq!(params.position, lsp::Position::new(0, 7));
+ Ok(Some(lsp::PrepareRenameResponse::Range(lsp::Range::new(
+ lsp::Position::new(0, 6),
+ lsp::Position::new(0, 9),
+ ))))
+ })
+ .next()
+ .await
+ .unwrap();
+ prepare_rename.await.unwrap();
+ editor_b.update(cx_b, |editor, cx| {
+ use editor::ToOffset;
+ let rename = editor.pending_rename().unwrap();
+ let buffer = editor.buffer().read(cx).snapshot(cx);
+ assert_eq!(
+ rename.range.start.to_offset(&buffer)..rename.range.end.to_offset(&buffer),
+ 6..9
+ );
+ rename.editor.update(cx, |rename_editor, cx| {
+ rename_editor.buffer().update(cx, |rename_buffer, cx| {
+ rename_buffer.edit([(0..3, "THREE")], None, cx);
+ });
+ });
+ });
+
+ let confirm_rename = editor_b.update(cx_b, |editor, cx| {
+ Editor::confirm_rename(editor, &ConfirmRename, cx).unwrap()
+ });
+ fake_language_server
+ .handle_request::<lsp::request::Rename, _, _>(|params, _| async move {
+ assert_eq!(
+ params.text_document_position.text_document.uri.as_str(),
+ "file:///dir/one.rs"
+ );
+ assert_eq!(
+ params.text_document_position.position,
+ lsp::Position::new(0, 6)
+ );
+ assert_eq!(params.new_name, "THREE");
+ Ok(Some(lsp::WorkspaceEdit {
+ changes: Some(
+ [
+ (
+ lsp::Url::from_file_path("/dir/one.rs").unwrap(),
+ vec![lsp::TextEdit::new(
+ lsp::Range::new(lsp::Position::new(0, 6), lsp::Position::new(0, 9)),
+ "THREE".to_string(),
+ )],
+ ),
+ (
+ lsp::Url::from_file_path("/dir/two.rs").unwrap(),
+ vec![
+ lsp::TextEdit::new(
+ lsp::Range::new(
+ lsp::Position::new(0, 24),
+ lsp::Position::new(0, 27),
+ ),
+ "THREE".to_string(),
+ ),
+ lsp::TextEdit::new(
+ lsp::Range::new(
+ lsp::Position::new(0, 35),
+ lsp::Position::new(0, 38),
+ ),
+ "THREE".to_string(),
+ ),
+ ],
+ ),
+ ]
+ .into_iter()
+ .collect(),
+ ),
+ ..Default::default()
+ }))
+ })
+ .next()
+ .await
+ .unwrap();
+ confirm_rename.await.unwrap();
+
+ let rename_editor = workspace_b.update(cx_b, |workspace, cx| {
+ workspace.active_item_as::<Editor>(cx).unwrap()
+ });
+
+ rename_editor.update(cx_b, |editor, cx| {
+ assert_eq!(
+ editor.text(cx),
+ "const THREE: usize = 1;\nconst TWO: usize = one::THREE + one::THREE;"
+ );
+ editor.undo(&Undo, cx);
+ assert_eq!(
+ editor.text(cx),
+ "const ONE: usize = 1;\nconst TWO: usize = one::ONE + one::ONE;"
+ );
+ editor.redo(&Redo, cx);
+ assert_eq!(
+ editor.text(cx),
+ "const THREE: usize = 1;\nconst TWO: usize = one::THREE + one::THREE;"
+ );
+ });
+
+ // Ensure temporary rename edits cannot be undone/redone.
+ editor_b.update(cx_b, |editor, cx| {
+ editor.undo(&Undo, cx);
+ assert_eq!(editor.text(cx), "const ONE: usize = 1;");
+ editor.undo(&Undo, cx);
+ assert_eq!(editor.text(cx), "const ONE: usize = 1;");
+ editor.redo(&Redo, cx);
+ assert_eq!(editor.text(cx), "const THREE: usize = 1;");
+ })
+}
+
+#[gpui::test(iterations = 10)]
+async fn test_language_server_statuses(cx_a: &mut TestAppContext, cx_b: &mut TestAppContext) {
+ let mut server = TestServer::start(cx_a.executor()).await;
+ let executor = cx_a.executor();
+ let client_a = server.create_client(cx_a, "user_a").await;
+ let client_b = server.create_client(cx_b, "user_b").await;
+ server
+ .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
+ .await;
+ let active_call_a = cx_a.read(ActiveCall::global);
+
+ cx_b.update(editor::init);
+
+ // Set up a fake language server.
+ let mut language = Language::new(
+ LanguageConfig {
+ name: "Rust".into(),
+ path_suffixes: vec!["rs".to_string()],
+ ..Default::default()
+ },
+ Some(tree_sitter_rust::language()),
+ );
+ let mut fake_language_servers = language
+ .set_fake_lsp_adapter(Arc::new(FakeLspAdapter {
+ name: "the-language-server",
+ ..Default::default()
+ }))
+ .await;
+ client_a.language_registry().add(Arc::new(language));
+
+ client_a
+ .fs()
+ .insert_tree(
+ "/dir",
+ json!({
+ "main.rs": "const ONE: usize = 1;",
+ }),
+ )
+ .await;
+ let (project_a, worktree_id) = client_a.build_local_project("/dir", cx_a).await;
+
+ let _buffer_a = project_a
+ .update(cx_a, |p, cx| p.open_buffer((worktree_id, "main.rs"), cx))
+ .await
+ .unwrap();
+
+ let fake_language_server = fake_language_servers.next().await.unwrap();
+ fake_language_server.start_progress("the-token").await;
+ fake_language_server.notify::<lsp::notification::Progress>(lsp::ProgressParams {
+ token: lsp::NumberOrString::String("the-token".to_string()),
+ value: lsp::ProgressParamsValue::WorkDone(lsp::WorkDoneProgress::Report(
+ lsp::WorkDoneProgressReport {
+ message: Some("the-message".to_string()),
+ ..Default::default()
+ },
+ )),
+ });
+ executor.run_until_parked();
+
+ project_a.read_with(cx_a, |project, _| {
+ let status = project.language_server_statuses().next().unwrap();
+ assert_eq!(status.name, "the-language-server");
+ assert_eq!(status.pending_work.len(), 1);
+ assert_eq!(
+ status.pending_work["the-token"].message.as_ref().unwrap(),
+ "the-message"
+ );
+ });
+
+ let project_id = active_call_a
+ .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
+ .await
+ .unwrap();
+ executor.run_until_parked();
+ let project_b = client_b.build_remote_project(project_id, cx_b).await;
+
+ project_b.read_with(cx_b, |project, _| {
+ let status = project.language_server_statuses().next().unwrap();
+ assert_eq!(status.name, "the-language-server");
+ });
+
+ fake_language_server.notify::<lsp::notification::Progress>(lsp::ProgressParams {
+ token: lsp::NumberOrString::String("the-token".to_string()),
+ value: lsp::ProgressParamsValue::WorkDone(lsp::WorkDoneProgress::Report(
+ lsp::WorkDoneProgressReport {
+ message: Some("the-message-2".to_string()),
+ ..Default::default()
+ },
+ )),
+ });
+ executor.run_until_parked();
+
+ project_a.read_with(cx_a, |project, _| {
+ let status = project.language_server_statuses().next().unwrap();
+ assert_eq!(status.name, "the-language-server");
+ assert_eq!(status.pending_work.len(), 1);
+ assert_eq!(
+ status.pending_work["the-token"].message.as_ref().unwrap(),
+ "the-message-2"
+ );
+ });
+
+ project_b.read_with(cx_b, |project, _| {
+ let status = project.language_server_statuses().next().unwrap();
+ assert_eq!(status.name, "the-language-server");
+ assert_eq!(status.pending_work.len(), 1);
+ assert_eq!(
+ status.pending_work["the-token"].message.as_ref().unwrap(),
+ "the-message-2"
+ );
+ });
+}
+
+#[gpui::test(iterations = 10)]
+async fn test_share_project(
+ cx_a: &mut TestAppContext,
+ cx_b: &mut TestAppContext,
+ cx_c: &mut TestAppContext,
+) {
+ let executor = cx_a.executor();
+ let window_b = cx_b.add_empty_window();
+ let mut server = TestServer::start(executor.clone()).await;
+ let client_a = server.create_client(cx_a, "user_a").await;
+ let client_b = server.create_client(cx_b, "user_b").await;
+ let client_c = server.create_client(cx_c, "user_c").await;
+ server
+ .make_contacts(&mut [(&client_a, cx_a), (&client_b, cx_b), (&client_c, cx_c)])
+ .await;
+ let active_call_a = cx_a.read(ActiveCall::global);
+ let active_call_b = cx_b.read(ActiveCall::global);
+ let active_call_c = cx_c.read(ActiveCall::global);
+
+ client_a
+ .fs()
+ .insert_tree(
+ "/a",
+ json!({
+ ".gitignore": "ignored-dir",
+ "a.txt": "a-contents",
+ "b.txt": "b-contents",
+ "ignored-dir": {
+ "c.txt": "",
+ "d.txt": "",
+ }
+ }),
+ )
+ .await;
+
+ // Invite client B to collaborate on a project
+ let (project_a, worktree_id) = client_a.build_local_project("/a", cx_a).await;
+ active_call_a
+ .update(cx_a, |call, cx| {
+ call.invite(client_b.user_id().unwrap(), Some(project_a.clone()), cx)
+ })
+ .await
+ .unwrap();
+
+ // Join that project as client B
+
+ let incoming_call_b = active_call_b.read_with(cx_b, |call, _| call.incoming());
+ executor.run_until_parked();
+ let call = incoming_call_b.borrow().clone().unwrap();
+ assert_eq!(call.calling_user.github_login, "user_a");
+ let initial_project = call.initial_project.unwrap();
+ active_call_b
+ .update(cx_b, |call, cx| call.accept_incoming(cx))
+ .await
+ .unwrap();
+ let client_b_peer_id = client_b.peer_id().unwrap();
+ let project_b = client_b
+ .build_remote_project(initial_project.id, cx_b)
+ .await;
+
+ let replica_id_b = project_b.read_with(cx_b, |project, _| project.replica_id());
+
+ executor.run_until_parked();
+
+ project_a.read_with(cx_a, |project, _| {
+ let client_b_collaborator = project.collaborators().get(&client_b_peer_id).unwrap();
+ assert_eq!(client_b_collaborator.replica_id, replica_id_b);
+ });
+
+ project_b.read_with(cx_b, |project, cx| {
+ let worktree = project.worktrees().next().unwrap().read(cx);
+ assert_eq!(
+ worktree.paths().map(AsRef::as_ref).collect::<Vec<_>>(),
+ [
+ Path::new(".gitignore"),
+ Path::new("a.txt"),
+ Path::new("b.txt"),
+ Path::new("ignored-dir"),
+ ]
+ );
+ });
+
+ project_b
+ .update(cx_b, |project, cx| {
+ let worktree = project.worktrees().next().unwrap();
+ let entry = worktree.read(cx).entry_for_path("ignored-dir").unwrap();
+ project.expand_entry(worktree_id, entry.id, cx).unwrap()
+ })
+ .await
+ .unwrap();
+
+ project_b.read_with(cx_b, |project, cx| {
+ let worktree = project.worktrees().next().unwrap().read(cx);
+ assert_eq!(
+ worktree.paths().map(AsRef::as_ref).collect::<Vec<_>>(),
+ [
+ Path::new(".gitignore"),
+ Path::new("a.txt"),
+ Path::new("b.txt"),
+ Path::new("ignored-dir"),
+ Path::new("ignored-dir/c.txt"),
+ Path::new("ignored-dir/d.txt"),
+ ]
+ );
+ });
+
+ // Open the same file as client B and client A.
+ let buffer_b = project_b
+ .update(cx_b, |p, cx| p.open_buffer((worktree_id, "b.txt"), cx))
+ .await
+ .unwrap();
+
+ buffer_b.read_with(cx_b, |buf, _| assert_eq!(buf.text(), "b-contents"));
+
+ project_a.read_with(cx_a, |project, cx| {
+ assert!(project.has_open_buffer((worktree_id, "b.txt"), cx))
+ });
+ let buffer_a = project_a
+ .update(cx_a, |p, cx| p.open_buffer((worktree_id, "b.txt"), cx))
+ .await
+ .unwrap();
+
+ let editor_b = window_b.build_view(cx_b, |cx| Editor::for_buffer(buffer_b, None, cx));
+
+ // Client A sees client B's selection
+ executor.run_until_parked();
+
+ buffer_a.read_with(cx_a, |buffer, _| {
+ buffer
+ .snapshot()
+ .remote_selections_in_range(text::Anchor::MIN..text::Anchor::MAX)
+ .count()
+ == 1
+ });
+
+ // Edit the buffer as client B and see that edit as client A.
+ let mut cx_b = VisualTestContext::from_window(window_b, cx_b);
+ editor_b.update(&mut cx_b, |editor, cx| editor.handle_input("ok, ", cx));
+ executor.run_until_parked();
+
+ buffer_a.read_with(cx_a, |buffer, _| {
+ assert_eq!(buffer.text(), "ok, b-contents")
+ });
+
+ // Client B can invite client C on a project shared by client A.
+ active_call_b
+ .update(&mut cx_b, |call, cx| {
+ call.invite(client_c.user_id().unwrap(), Some(project_b.clone()), cx)
+ })
+ .await
+ .unwrap();
+
+ let incoming_call_c = active_call_c.read_with(cx_c, |call, _| call.incoming());
+ executor.run_until_parked();
+ let call = incoming_call_c.borrow().clone().unwrap();
+ assert_eq!(call.calling_user.github_login, "user_b");
+ let initial_project = call.initial_project.unwrap();
+ active_call_c
+ .update(cx_c, |call, cx| call.accept_incoming(cx))
+ .await
+ .unwrap();
+ let _project_c = client_c
+ .build_remote_project(initial_project.id, cx_c)
+ .await;
+
+ // Client B closes the editor, and client A sees client B's selections removed.
+ cx_b.update(move |_| drop(editor_b));
+ executor.run_until_parked();
+
+ buffer_a.read_with(cx_a, |buffer, _| {
+ buffer
+ .snapshot()
+ .remote_selections_in_range(text::Anchor::MIN..text::Anchor::MAX)
+ .count()
+ == 0
+ });
+}
+
+#[gpui::test(iterations = 10)]
+async fn test_on_input_format_from_host_to_guest(
+ cx_a: &mut TestAppContext,
+ cx_b: &mut TestAppContext,
+) {
+ let mut server = TestServer::start(cx_a.executor()).await;
+ let executor = cx_a.executor();
+ let client_a = server.create_client(cx_a, "user_a").await;
+ let client_b = server.create_client(cx_b, "user_b").await;
+ server
+ .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
+ .await;
+ let active_call_a = cx_a.read(ActiveCall::global);
+
+ // Set up a fake language server.
+ let mut language = Language::new(
+ LanguageConfig {
+ name: "Rust".into(),
+ path_suffixes: vec!["rs".to_string()],
+ ..Default::default()
+ },
+ Some(tree_sitter_rust::language()),
+ );
+ let mut fake_language_servers = language
+ .set_fake_lsp_adapter(Arc::new(FakeLspAdapter {
+ capabilities: lsp::ServerCapabilities {
+ document_on_type_formatting_provider: Some(lsp::DocumentOnTypeFormattingOptions {
+ first_trigger_character: ":".to_string(),
+ more_trigger_character: Some(vec![">".to_string()]),
+ }),
+ ..Default::default()
+ },
+ ..Default::default()
+ }))
+ .await;
+ client_a.language_registry().add(Arc::new(language));
+
+ client_a
+ .fs()
+ .insert_tree(
+ "/a",
+ json!({
+ "main.rs": "fn main() { a }",
+ "other.rs": "// Test file",
+ }),
+ )
+ .await;
+ let (project_a, worktree_id) = client_a.build_local_project("/a", cx_a).await;
+ let project_id = active_call_a
+ .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
+ .await
+ .unwrap();
+ let project_b = client_b.build_remote_project(project_id, cx_b).await;
+
+ // Open a file in an editor as the host.
+ let buffer_a = project_a
+ .update(cx_a, |p, cx| p.open_buffer((worktree_id, "main.rs"), cx))
+ .await
+ .unwrap();
+ let window_a = cx_a.add_empty_window();
+ let editor_a = window_a
+ .update(cx_a, |_, cx| {
+ cx.new_view(|cx| Editor::for_buffer(buffer_a, Some(project_a.clone()), cx))
+ })
+ .unwrap();
+
+ let fake_language_server = fake_language_servers.next().await.unwrap();
+ executor.run_until_parked();
+
+ // Receive an OnTypeFormatting request as the host's language server.
+ // Return some formattings from the host's language server.
+ fake_language_server.handle_request::<lsp::request::OnTypeFormatting, _, _>(
+ |params, _| async move {
+ assert_eq!(
+ params.text_document_position.text_document.uri,
+ lsp::Url::from_file_path("/a/main.rs").unwrap(),
+ );
+ assert_eq!(
+ params.text_document_position.position,
+ lsp::Position::new(0, 14),
+ );
+
+ Ok(Some(vec![lsp::TextEdit {
+ new_text: "~<".to_string(),
+ range: lsp::Range::new(lsp::Position::new(0, 14), lsp::Position::new(0, 14)),
+ }]))
+ },
+ );
+
+ // Open the buffer on the guest and see that the formattings worked
+ let buffer_b = project_b
+ .update(cx_b, |p, cx| p.open_buffer((worktree_id, "main.rs"), cx))
+ .await
+ .unwrap();
+
+ let mut cx_a = VisualTestContext::from_window(window_a, cx_a);
+ // Type a on type formatting trigger character as the guest.
+ cx_a.focus_view(&editor_a);
+ editor_a.update(&mut cx_a, |editor, cx| {
+ editor.change_selections(None, cx, |s| s.select_ranges([13..13]));
+ editor.handle_input(">", cx);
+ });
+
+ executor.run_until_parked();
+
+ buffer_b.read_with(cx_b, |buffer, _| {
+ assert_eq!(buffer.text(), "fn main() { a>~< }")
+ });
+
+ // Undo should remove LSP edits first
+ editor_a.update(&mut cx_a, |editor, cx| {
+ assert_eq!(editor.text(cx), "fn main() { a>~< }");
+ editor.undo(&Undo, cx);
+ assert_eq!(editor.text(cx), "fn main() { a> }");
+ });
+ executor.run_until_parked();
+
+ buffer_b.read_with(cx_b, |buffer, _| {
+ assert_eq!(buffer.text(), "fn main() { a> }")
+ });
+
+ editor_a.update(&mut cx_a, |editor, cx| {
+ assert_eq!(editor.text(cx), "fn main() { a> }");
+ editor.undo(&Undo, cx);
+ assert_eq!(editor.text(cx), "fn main() { a }");
+ });
+ executor.run_until_parked();
+
+ buffer_b.read_with(cx_b, |buffer, _| {
+ assert_eq!(buffer.text(), "fn main() { a }")
+ });
+}
+
+#[gpui::test(iterations = 10)]
+async fn test_on_input_format_from_guest_to_host(
+ cx_a: &mut TestAppContext,
+ cx_b: &mut TestAppContext,
+) {
+ let mut server = TestServer::start(cx_a.executor()).await;
+ let executor = cx_a.executor();
+ let client_a = server.create_client(cx_a, "user_a").await;
+ let client_b = server.create_client(cx_b, "user_b").await;
+ server
+ .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
+ .await;
+ let active_call_a = cx_a.read(ActiveCall::global);
+
+ // Set up a fake language server.
+ let mut language = Language::new(
+ LanguageConfig {
+ name: "Rust".into(),
+ path_suffixes: vec!["rs".to_string()],
+ ..Default::default()
+ },
+ Some(tree_sitter_rust::language()),
+ );
+ let mut fake_language_servers = language
+ .set_fake_lsp_adapter(Arc::new(FakeLspAdapter {
+ capabilities: lsp::ServerCapabilities {
+ document_on_type_formatting_provider: Some(lsp::DocumentOnTypeFormattingOptions {
+ first_trigger_character: ":".to_string(),
+ more_trigger_character: Some(vec![">".to_string()]),
+ }),
+ ..Default::default()
+ },
+ ..Default::default()
+ }))
+ .await;
+ client_a.language_registry().add(Arc::new(language));
+
+ client_a
+ .fs()
+ .insert_tree(
+ "/a",
+ json!({
+ "main.rs": "fn main() { a }",
+ "other.rs": "// Test file",
+ }),
+ )
+ .await;
+ let (project_a, worktree_id) = client_a.build_local_project("/a", cx_a).await;
+ let project_id = active_call_a
+ .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
+ .await
+ .unwrap();
+ let project_b = client_b.build_remote_project(project_id, cx_b).await;
+
+ // Open a file in an editor as the guest.
+ let buffer_b = project_b
+ .update(cx_b, |p, cx| p.open_buffer((worktree_id, "main.rs"), cx))
+ .await
+ .unwrap();
+ let window_b = cx_b.add_empty_window();
+ let editor_b = window_b.build_view(cx_b, |cx| {
+ Editor::for_buffer(buffer_b, Some(project_b.clone()), cx)
+ });
+
+ let fake_language_server = fake_language_servers.next().await.unwrap();
+ executor.run_until_parked();
+ let mut cx_b = VisualTestContext::from_window(window_b, cx_b);
+ // Type a on type formatting trigger character as the guest.
+ cx_b.focus_view(&editor_b);
+ editor_b.update(&mut cx_b, |editor, cx| {
+ editor.change_selections(None, cx, |s| s.select_ranges([13..13]));
+ editor.handle_input(":", cx);
+ });
+
+ // Receive an OnTypeFormatting request as the host's language server.
+ // Return some formattings from the host's language server.
+ executor.start_waiting();
+ fake_language_server
+ .handle_request::<lsp::request::OnTypeFormatting, _, _>(|params, _| async move {
+ assert_eq!(
+ params.text_document_position.text_document.uri,
+ lsp::Url::from_file_path("/a/main.rs").unwrap(),
+ );
+ assert_eq!(
+ params.text_document_position.position,
+ lsp::Position::new(0, 14),
+ );
+
+ Ok(Some(vec![lsp::TextEdit {
+ new_text: "~:".to_string(),
+ range: lsp::Range::new(lsp::Position::new(0, 14), lsp::Position::new(0, 14)),
+ }]))
+ })
+ .next()
+ .await
+ .unwrap();
+ executor.finish_waiting();
+
+ // Open the buffer on the host and see that the formattings worked
+ let buffer_a = project_a
+ .update(cx_a, |p, cx| p.open_buffer((worktree_id, "main.rs"), cx))
+ .await
+ .unwrap();
+ executor.run_until_parked();
+
+ buffer_a.read_with(cx_a, |buffer, _| {
+ assert_eq!(buffer.text(), "fn main() { a:~: }")
+ });
+
+ // Undo should remove LSP edits first
+ editor_b.update(&mut cx_b, |editor, cx| {
+ assert_eq!(editor.text(cx), "fn main() { a:~: }");
+ editor.undo(&Undo, cx);
+ assert_eq!(editor.text(cx), "fn main() { a: }");
+ });
+ executor.run_until_parked();
+
+ buffer_a.read_with(cx_a, |buffer, _| {
+ assert_eq!(buffer.text(), "fn main() { a: }")
+ });
+
+ editor_b.update(&mut cx_b, |editor, cx| {
+ assert_eq!(editor.text(cx), "fn main() { a: }");
+ editor.undo(&Undo, cx);
+ assert_eq!(editor.text(cx), "fn main() { a }");
+ });
+ executor.run_until_parked();
+
+ buffer_a.read_with(cx_a, |buffer, _| {
+ assert_eq!(buffer.text(), "fn main() { a }")
+ });
+}
+
+#[gpui::test(iterations = 10)]
+async fn test_mutual_editor_inlay_hint_cache_update(
+ cx_a: &mut TestAppContext,
+ cx_b: &mut TestAppContext,
+) {
+ let mut server = TestServer::start(cx_a.executor()).await;
+ let executor = cx_a.executor();
+ let client_a = server.create_client(cx_a, "user_a").await;
+ let client_b = server.create_client(cx_b, "user_b").await;
+ server
+ .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
+ .await;
+ let active_call_a = cx_a.read(ActiveCall::global);
+ let active_call_b = cx_b.read(ActiveCall::global);
+
+ cx_a.update(editor::init);
+ cx_b.update(editor::init);
+
+ cx_a.update(|cx| {
+ cx.update_global(|store: &mut SettingsStore, cx| {
+ store.update_user_settings::<AllLanguageSettings>(cx, |settings| {
+ settings.defaults.inlay_hints = Some(InlayHintSettings {
+ enabled: true,
+ show_type_hints: true,
+ show_parameter_hints: false,
+ show_other_hints: true,
+ })
+ });
+ });
+ });
+ cx_b.update(|cx| {
+ cx.update_global(|store: &mut SettingsStore, cx| {
+ store.update_user_settings::<AllLanguageSettings>(cx, |settings| {
+ settings.defaults.inlay_hints = Some(InlayHintSettings {
+ enabled: true,
+ show_type_hints: true,
+ show_parameter_hints: false,
+ show_other_hints: true,
+ })
+ });
+ });
+ });
+
+ let mut language = Language::new(
+ LanguageConfig {
+ name: "Rust".into(),
+ path_suffixes: vec!["rs".to_string()],
+ ..Default::default()
+ },
+ Some(tree_sitter_rust::language()),
+ );
+ let mut fake_language_servers = language
+ .set_fake_lsp_adapter(Arc::new(FakeLspAdapter {
+ capabilities: lsp::ServerCapabilities {
+ inlay_hint_provider: Some(lsp::OneOf::Left(true)),
+ ..Default::default()
+ },
+ ..Default::default()
+ }))
+ .await;
+ let language = Arc::new(language);
+ client_a.language_registry().add(Arc::clone(&language));
+ client_b.language_registry().add(language);
+
+ // Client A opens a project.
+ client_a
+ .fs()
+ .insert_tree(
+ "/a",
+ json!({
+ "main.rs": "fn main() { a } // and some long comment to ensure inlay hints are not trimmed out",
+ "other.rs": "// Test file",
+ }),
+ )
+ .await;
+ let (project_a, worktree_id) = client_a.build_local_project("/a", cx_a).await;
+ active_call_a
+ .update(cx_a, |call, cx| call.set_location(Some(&project_a), cx))
+ .await
+ .unwrap();
+ let project_id = active_call_a
+ .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
+ .await
+ .unwrap();
+
+ // Client B joins the project
+ let project_b = client_b.build_remote_project(project_id, cx_b).await;
+ active_call_b
+ .update(cx_b, |call, cx| call.set_location(Some(&project_b), cx))
+ .await
+ .unwrap();
+
+ let (workspace_a, cx_a) = client_a.build_workspace(&project_a, cx_a);
+ executor.start_waiting();
+
+ // The host opens a rust file.
+ let _buffer_a = project_a
+ .update(cx_a, |project, cx| {
+ project.open_local_buffer("/a/main.rs", cx)
+ })
+ .await
+ .unwrap();
+ let fake_language_server = fake_language_servers.next().await.unwrap();
+ let editor_a = workspace_a
+ .update(cx_a, |workspace, cx| {
+ workspace.open_path((worktree_id, "main.rs"), None, true, cx)
+ })
+ .await
+ .unwrap()
+ .downcast::<Editor>()
+ .unwrap();
+
+ // Set up the language server to return an additional inlay hint on each request.
+ let edits_made = Arc::new(AtomicUsize::new(0));
+ let closure_edits_made = Arc::clone(&edits_made);
+ fake_language_server
+ .handle_request::<lsp::request::InlayHintRequest, _, _>(move |params, _| {
+ let task_edits_made = Arc::clone(&closure_edits_made);
+ async move {
+ assert_eq!(
+ params.text_document.uri,
+ lsp::Url::from_file_path("/a/main.rs").unwrap(),
+ );
+ let edits_made = task_edits_made.load(atomic::Ordering::Acquire);
+ Ok(Some(vec![lsp::InlayHint {
+ position: lsp::Position::new(0, edits_made as u32),
+ label: lsp::InlayHintLabel::String(edits_made.to_string()),
+ kind: None,
+ text_edits: None,
+ tooltip: None,
+ padding_left: None,
+ padding_right: None,
+ data: None,
+ }]))
+ }
+ })
+ .next()
+ .await
+ .unwrap();
+
+ executor.run_until_parked();
+
+ let initial_edit = edits_made.load(atomic::Ordering::Acquire);
+ editor_a.update(cx_a, |editor, _| {
+ assert_eq!(
+ vec![initial_edit.to_string()],
+ extract_hint_labels(editor),
+ "Host should get its first hints when opens an editor"
+ );
+ let inlay_cache = editor.inlay_hint_cache();
+ assert_eq!(
+ inlay_cache.version(),
+ 1,
+ "Host editor update the cache version after every cache/view change",
+ );
+ });
+ let (workspace_b, cx_b) = client_b.build_workspace(&project_b, cx_b);
+ let editor_b = workspace_b
+ .update(cx_b, |workspace, cx| {
+ workspace.open_path((worktree_id, "main.rs"), None, true, cx)
+ })
+ .await
+ .unwrap()
+ .downcast::<Editor>()
+ .unwrap();
+
+ executor.run_until_parked();
+ editor_b.update(cx_b, |editor, _| {
+ assert_eq!(
+ vec![initial_edit.to_string()],
+ extract_hint_labels(editor),
+ "Client should get its first hints when opens an editor"
+ );
+ let inlay_cache = editor.inlay_hint_cache();
+ assert_eq!(
+ inlay_cache.version(),
+ 1,
+ "Guest editor update the cache version after every cache/view change"
+ );
+ });
+
+ let after_client_edit = edits_made.fetch_add(1, atomic::Ordering::Release) + 1;
+ editor_b.update(cx_b, |editor, cx| {
+ editor.change_selections(None, cx, |s| s.select_ranges([13..13].clone()));
+ editor.handle_input(":", cx);
+ });
+ cx_b.focus_view(&editor_b);
+
+ executor.run_until_parked();
+ editor_a.update(cx_a, |editor, _| {
+ assert_eq!(
+ vec![after_client_edit.to_string()],
+ extract_hint_labels(editor),
+ );
+ let inlay_cache = editor.inlay_hint_cache();
+ assert_eq!(inlay_cache.version(), 2);
+ });
+ editor_b.update(cx_b, |editor, _| {
+ assert_eq!(
+ vec![after_client_edit.to_string()],
+ extract_hint_labels(editor),
+ );
+ let inlay_cache = editor.inlay_hint_cache();
+ assert_eq!(inlay_cache.version(), 2);
+ });
+
+ let after_host_edit = edits_made.fetch_add(1, atomic::Ordering::Release) + 1;
+ editor_a.update(cx_a, |editor, cx| {
+ editor.change_selections(None, cx, |s| s.select_ranges([13..13]));
+ editor.handle_input("a change to increment both buffers' versions", cx);
+ });
+ cx_a.focus_view(&editor_a);
+
+ executor.run_until_parked();
+ editor_a.update(cx_a, |editor, _| {
+ assert_eq!(
+ vec![after_host_edit.to_string()],
+ extract_hint_labels(editor),
+ );
+ let inlay_cache = editor.inlay_hint_cache();
+ assert_eq!(inlay_cache.version(), 3);
+ });
+ editor_b.update(cx_b, |editor, _| {
+ assert_eq!(
+ vec![after_host_edit.to_string()],
+ extract_hint_labels(editor),
+ );
+ let inlay_cache = editor.inlay_hint_cache();
+ assert_eq!(inlay_cache.version(), 3);
+ });
+
+ let after_special_edit_for_refresh = edits_made.fetch_add(1, atomic::Ordering::Release) + 1;
+ fake_language_server
+ .request::<lsp::request::InlayHintRefreshRequest>(())
+ .await
+ .expect("inlay refresh request failed");
+
+ executor.run_until_parked();
+ editor_a.update(cx_a, |editor, _| {
+ assert_eq!(
+ vec![after_special_edit_for_refresh.to_string()],
+ extract_hint_labels(editor),
+ "Host should react to /refresh LSP request"
+ );
+ let inlay_cache = editor.inlay_hint_cache();
+ assert_eq!(
+ inlay_cache.version(),
+ 4,
+ "Host should accepted all edits and bump its cache version every time"
+ );
+ });
+ editor_b.update(cx_b, |editor, _| {
+ assert_eq!(
+ vec![after_special_edit_for_refresh.to_string()],
+ extract_hint_labels(editor),
+ "Guest should get a /refresh LSP request propagated by host"
+ );
+ let inlay_cache = editor.inlay_hint_cache();
+ assert_eq!(
+ inlay_cache.version(),
+ 4,
+ "Guest should accepted all edits and bump its cache version every time"
+ );
+ });
+}
+
+#[gpui::test(iterations = 10)]
+async fn test_inlay_hint_refresh_is_forwarded(
+ cx_a: &mut TestAppContext,
+ cx_b: &mut TestAppContext,
+) {
+ let mut server = TestServer::start(cx_a.executor()).await;
+ let executor = cx_a.executor();
+ let client_a = server.create_client(cx_a, "user_a").await;
+ let client_b = server.create_client(cx_b, "user_b").await;
+ server
+ .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)])
+ .await;
+ let active_call_a = cx_a.read(ActiveCall::global);
+ let active_call_b = cx_b.read(ActiveCall::global);
+
+ cx_a.update(editor::init);
+ cx_b.update(editor::init);
+
+ cx_a.update(|cx| {
+ cx.update_global(|store: &mut SettingsStore, cx| {
+ store.update_user_settings::<AllLanguageSettings>(cx, |settings| {
+ settings.defaults.inlay_hints = Some(InlayHintSettings {
+ enabled: false,
+ show_type_hints: false,
+ show_parameter_hints: false,
+ show_other_hints: false,
+ })
+ });
+ });
+ });
+ cx_b.update(|cx| {
+ cx.update_global(|store: &mut SettingsStore, cx| {
+ store.update_user_settings::<AllLanguageSettings>(cx, |settings| {
+ settings.defaults.inlay_hints = Some(InlayHintSettings {
+ enabled: true,
+ show_type_hints: true,
+ show_parameter_hints: true,
+ show_other_hints: true,
+ })
+ });
+ });
+ });
+
+ let mut language = Language::new(
+ LanguageConfig {
+ name: "Rust".into(),
+ path_suffixes: vec!["rs".to_string()],
+ ..Default::default()
+ },
+ Some(tree_sitter_rust::language()),
+ );
+ let mut fake_language_servers = language
+ .set_fake_lsp_adapter(Arc::new(FakeLspAdapter {
+ capabilities: lsp::ServerCapabilities {
+ inlay_hint_provider: Some(lsp::OneOf::Left(true)),
+ ..Default::default()
+ },
+ ..Default::default()
+ }))
+ .await;
+ let language = Arc::new(language);
+ client_a.language_registry().add(Arc::clone(&language));
+ client_b.language_registry().add(language);
+
+ client_a
+ .fs()
+ .insert_tree(
+ "/a",
+ json!({
+ "main.rs": "fn main() { a } // and some long comment to ensure inlay hints are not trimmed out",
+ "other.rs": "// Test file",
+ }),
+ )
+ .await;
+ let (project_a, worktree_id) = client_a.build_local_project("/a", cx_a).await;
+ active_call_a
+ .update(cx_a, |call, cx| call.set_location(Some(&project_a), cx))
+ .await
+ .unwrap();
+ let project_id = active_call_a
+ .update(cx_a, |call, cx| call.share_project(project_a.clone(), cx))
+ .await
+ .unwrap();
+
+ let project_b = client_b.build_remote_project(project_id, cx_b).await;
+ active_call_b
+ .update(cx_b, |call, cx| call.set_location(Some(&project_b), cx))
+ .await
+ .unwrap();
+
+ let (workspace_a, cx_a) = client_a.build_workspace(&project_a, cx_a);
+ let (workspace_b, cx_b) = client_b.build_workspace(&project_b, cx_b);
+
+ cx_a.background_executor.start_waiting();
+
+ let editor_a = workspace_a
+ .update(cx_a, |workspace, cx| {
+ workspace.open_path((worktree_id, "main.rs"), None, true, cx)
+ })
+ .await
+ .unwrap()
+ .downcast::<Editor>()
+ .unwrap();
+
+ let editor_b = workspace_b
+ .update(cx_b, |workspace, cx| {
+ workspace.open_path((worktree_id, "main.rs"), None, true, cx)
+ })
+ .await
+ .unwrap()
+ .downcast::<Editor>()
+ .unwrap();
+
+ let other_hints = Arc::new(AtomicBool::new(false));
+ let fake_language_server = fake_language_servers.next().await.unwrap();
+ let closure_other_hints = Arc::clone(&other_hints);
+ fake_language_server
+ .handle_request::<lsp::request::InlayHintRequest, _, _>(move |params, _| {
+ let task_other_hints = Arc::clone(&closure_other_hints);
+ async move {
+ assert_eq!(
+ params.text_document.uri,
+ lsp::Url::from_file_path("/a/main.rs").unwrap(),
+ );
+ let other_hints = task_other_hints.load(atomic::Ordering::Acquire);
+ let character = if other_hints { 0 } else { 2 };
+ let label = if other_hints {
+ "other hint"
+ } else {
+ "initial hint"
+ };
+ Ok(Some(vec![lsp::InlayHint {
+ position: lsp::Position::new(0, character),
+ label: lsp::InlayHintLabel::String(label.to_string()),
+ kind: None,
+ text_edits: None,
+ tooltip: None,
+ padding_left: None,
+ padding_right: None,
+ data: None,
+ }]))
+ }
+ })
+ .next()
+ .await
+ .unwrap();
+ executor.finish_waiting();
+
+ executor.run_until_parked();
+ editor_a.update(cx_a, |editor, _| {
+ assert!(
+ extract_hint_labels(editor).is_empty(),
+ "Host should get no hints due to them turned off"
+ );
+ let inlay_cache = editor.inlay_hint_cache();
+ assert_eq!(
+ inlay_cache.version(),
+ 0,
+ "Turned off hints should not generate version updates"
+ );
+ });
+
+ executor.run_until_parked();
+ editor_b.update(cx_b, |editor, _| {
+ assert_eq!(
+ vec!["initial hint".to_string()],
+ extract_hint_labels(editor),
+ "Client should get its first hints when opens an editor"
+ );
+ let inlay_cache = editor.inlay_hint_cache();
+ assert_eq!(
+ inlay_cache.version(),
+ 1,
+ "Should update cache verison after first hints"
+ );
+ });
+
+ other_hints.fetch_or(true, atomic::Ordering::Release);
+ fake_language_server
+ .request::<lsp::request::InlayHintRefreshRequest>(())
+ .await
+ .expect("inlay refresh request failed");
+ executor.run_until_parked();
+ editor_a.update(cx_a, |editor, _| {
+ assert!(
+ extract_hint_labels(editor).is_empty(),
+ "Host should get nop hints due to them turned off, even after the /refresh"
+ );
+ let inlay_cache = editor.inlay_hint_cache();
+ assert_eq!(
+ inlay_cache.version(),
+ 0,
+ "Turned off hints should not generate version updates, again"
+ );
+ });
+
+ executor.run_until_parked();
+ editor_b.update(cx_b, |editor, _| {
+ assert_eq!(
+ vec!["other hint".to_string()],
+ extract_hint_labels(editor),
+ "Guest should get a /refresh LSP request propagated by host despite host hints are off"
+ );
+ let inlay_cache = editor.inlay_hint_cache();
+ assert_eq!(
+ inlay_cache.version(),
+ 2,
+ "Guest should accepted all edits and bump its cache version every time"
+ );
+ });
+}
+
+fn extract_hint_labels(editor: &Editor) -> Vec<String> {
+ let mut labels = Vec::new();
+ for hint in editor.inlay_hint_cache().hints() {
+ match hint.label {
+ project::InlayHintLabel::String(s) => labels.push(s),
+ _ => unreachable!(),
+ }
+ }
+ labels
+}
@@ -19,6 +19,7 @@ use project::{
search::SearchQuery, DiagnosticSummary, FormatTrigger, HoverBlockKind, Project, ProjectPath,
};
use rand::prelude::*;
+use rpc::proto::ChannelRole;
use serde_json::json;
use settings::SettingsStore;
use std::{
@@ -1380,7 +1381,7 @@ async fn test_unshare_project(
.unwrap();
executor.run_until_parked();
- assert!(project_b.read_with(cx_b, |project, _| project.is_read_only()));
+ assert!(project_b.read_with(cx_b, |project, _| project.is_disconnected()));
// Client C opens the project.
let project_c = client_c.build_remote_project(project_id, cx_c).await;
@@ -1393,7 +1394,7 @@ async fn test_unshare_project(
assert!(worktree_a.read_with(cx_a, |tree, _| !tree.as_local().unwrap().is_shared()));
- assert!(project_c.read_with(cx_c, |project, _| project.is_read_only()));
+ assert!(project_c.read_with(cx_c, |project, _| project.is_disconnected()));
// Client C can open the project again after client A re-shares.
let project_id = active_call_a
@@ -1419,7 +1420,7 @@ async fn test_unshare_project(
project_a.read_with(cx_a, |project, _| assert!(!project.is_shared()));
project_c2.read_with(cx_c, |project, _| {
- assert!(project.is_read_only());
+ assert!(project.is_disconnected());
assert!(project.collaborators().is_empty());
});
}
@@ -1551,7 +1552,7 @@ async fn test_project_reconnect(
});
project_b1.read_with(cx_b, |project, _| {
- assert!(!project.is_read_only());
+ assert!(!project.is_disconnected());
assert_eq!(project.collaborators().len(), 1);
});
@@ -1653,7 +1654,7 @@ async fn test_project_reconnect(
});
project_b1.read_with(cx_b, |project, cx| {
- assert!(!project.is_read_only());
+ assert!(!project.is_disconnected());
assert_eq!(
project
.worktree_for_id(worktree1_id, cx)
@@ -1687,9 +1688,9 @@ async fn test_project_reconnect(
);
});
- project_b2.read_with(cx_b, |project, _| assert!(project.is_read_only()));
+ project_b2.read_with(cx_b, |project, _| assert!(project.is_disconnected()));
- project_b3.read_with(cx_b, |project, _| assert!(!project.is_read_only()));
+ project_b3.read_with(cx_b, |project, _| assert!(!project.is_disconnected()));
buffer_a1.read_with(cx_a, |buffer, _| assert_eq!(buffer.text(), "WaZ"));
@@ -1746,7 +1747,7 @@ async fn test_project_reconnect(
executor.run_until_parked();
project_b1.read_with(cx_b, |project, cx| {
- assert!(!project.is_read_only());
+ assert!(!project.is_disconnected());
assert_eq!(
project
.worktree_for_id(worktree1_id, cx)
@@ -1780,7 +1781,7 @@ async fn test_project_reconnect(
);
});
- project_b3.read_with(cx_b, |project, _| assert!(project.is_read_only()));
+ project_b3.read_with(cx_b, |project, _| assert!(project.is_disconnected()));
buffer_a1.read_with(cx_a, |buffer, _| assert_eq!(buffer.text(), "WXaYZ"));
@@ -3535,7 +3536,7 @@ async fn test_leaving_project(
});
project_b2.read_with(cx_b, |project, _| {
- assert!(project.is_read_only());
+ assert!(project.is_disconnected());
});
project_c.read_with(cx_c, |project, _| {
@@ -3550,6 +3551,7 @@ async fn test_leaving_project(
client_b.user_store().clone(),
client_b.language_registry().clone(),
FakeFs::new(cx.background_executor().clone()),
+ ChannelRole::Member,
cx,
)
})
@@ -3568,11 +3570,11 @@ async fn test_leaving_project(
});
project_b2.read_with(cx_b, |project, _| {
- assert!(project.is_read_only());
+ assert!(project.is_disconnected());
});
project_c.read_with(cx_c, |project, _| {
- assert!(project.is_read_only());
+ assert!(project.is_disconnected());
});
}
@@ -1149,7 +1149,7 @@ impl RandomizedTest for ProjectCollaborationTest {
Some((project, cx))
});
- if !guest_project.is_read_only() {
+ if !guest_project.is_disconnected() {
if let Some((host_project, host_cx)) = host_project {
let host_worktree_snapshots =
host_project.read_with(host_cx, |host_project, cx| {
@@ -1236,7 +1236,7 @@ impl RandomizedTest for ProjectCollaborationTest {
let buffers = client.buffers().clone();
for (guest_project, guest_buffers) in &buffers {
let project_id = if guest_project.read_with(client_cx, |project, _| {
- project.is_local() || project.is_read_only()
+ project.is_local() || project.is_disconnected()
}) {
continue;
} else {
@@ -518,7 +518,7 @@ impl<T: RandomizedTest> TestPlan<T> {
for project in client.remote_projects().iter() {
project.read_with(&client_cx, |project, _| {
assert!(
- project.is_read_only(),
+ project.is_disconnected(),
"project {:?} should be read only",
project.remote_id()
)
@@ -138,12 +138,6 @@ impl ChannelView {
editor.set_collaboration_hub(Box::new(ChannelBufferCollaborationHub(
channel_buffer.clone(),
)));
- editor.set_read_only(
- !channel_buffer
- .read(cx)
- .channel(cx)
- .is_some_and(|c| c.can_edit_notes()),
- );
editor
});
let _editor_event_subscription =
@@ -178,8 +172,7 @@ impl ChannelView {
cx.notify();
}),
ChannelBufferEvent::ChannelChanged => {
- self.editor.update(cx, |editor, cx| {
- editor.set_read_only(!self.channel(cx).is_some_and(|c| c.can_edit_notes()));
+ self.editor.update(cx, |_, cx| {
cx.emit(editor::EditorEvent::TitleChanged);
cx.notify()
});
@@ -254,11 +247,11 @@ impl Item for ChannelView {
fn tab_content(&self, _: Option<usize>, selected: bool, cx: &WindowContext) -> AnyElement {
let label = if let Some(channel) = self.channel(cx) {
match (
- channel.can_edit_notes(),
+ self.channel_buffer.read(cx).buffer().read(cx).read_only(),
self.channel_buffer.read(cx).is_connected(),
) {
- (true, true) => format!("#{}", channel.name),
- (false, true) => format!("#{} (read-only)", channel.name),
+ (false, true) => format!("#{}", channel.name),
+ (true, true) => format!("#{} (read-only)", channel.name),
(_, false) => format!("#{} (disconnected)", channel.name),
}
} else {
@@ -607,8 +607,12 @@ impl Panel for ChatPanel {
"ChatPanel"
}
- fn icon(&self, _cx: &WindowContext) -> Option<ui::Icon> {
- Some(ui::Icon::MessageBubbles)
+ fn icon(&self, cx: &WindowContext) -> Option<ui::Icon> {
+ if !is_channels_feature_enabled(cx) {
+ return None;
+ }
+
+ Some(ui::Icon::MessageBubbles).filter(|_| ChatPanelSettings::get_global(cx).button)
}
fn icon_tooltip(&self, _cx: &WindowContext) -> Option<&'static str> {
@@ -11,15 +11,16 @@ use channel::{Channel, ChannelEvent, ChannelId, ChannelStore};
use client::{Client, Contact, User, UserStore};
use contact_finder::ContactFinder;
use db::kvp::KEY_VALUE_STORE;
-use editor::Editor;
+use editor::{Editor, EditorElement, EditorStyle};
use feature_flags::{ChannelsAlpha, FeatureFlagAppExt, FeatureFlagViewExt};
use fuzzy::{match_strings, StringMatchCandidate};
use gpui::{
actions, canvas, div, fill, list, overlay, point, prelude::*, px, serde_json, AnyElement,
AppContext, AsyncWindowContext, Bounds, ClipboardItem, DismissEvent, Div, EventEmitter,
- FocusHandle, FocusableView, InteractiveElement, IntoElement, ListOffset, ListState, Model,
- MouseDownEvent, ParentElement, Pixels, Point, PromptLevel, Render, RenderOnce, SharedString,
- Styled, Subscription, Task, View, ViewContext, VisualContext, WeakView,
+ FocusHandle, FocusableView, FontStyle, FontWeight, InteractiveElement, IntoElement, ListOffset,
+ ListState, Model, MouseDownEvent, ParentElement, Pixels, Point, PromptLevel, Render,
+ RenderOnce, SharedString, Styled, Subscription, Task, TextStyle, View, ViewContext,
+ VisualContext, WeakView, WhiteSpace,
};
use menu::{Cancel, Confirm, SelectNext, SelectPrev};
use project::{Fs, Project};
@@ -29,10 +30,9 @@ use settings::{Settings, SettingsStore};
use smallvec::SmallVec;
use std::{mem, sync::Arc};
use theme::{ActiveTheme, ThemeSettings};
-use ui::prelude::*;
use ui::{
- h_stack, v_stack, Avatar, Button, Color, ContextMenu, Icon, IconButton, IconElement, IconSize,
- Label, ListHeader, ListItem, Tooltip,
+ prelude::*, Avatar, Button, Color, ContextMenu, Icon, IconButton, IconElement, IconSize, Label,
+ ListHeader, ListItem, Tooltip,
};
use util::{maybe, ResultExt, TryFutureExt};
use workspace::{
@@ -151,6 +151,10 @@ enum ListEntry {
peer_id: Option<PeerId>,
is_last: bool,
},
+ GuestCount {
+ count: usize,
+ has_visible_participants: bool,
+ },
IncomingRequest(Arc<User>),
OutgoingRequest(Arc<User>),
ChannelInvite(Arc<Channel>),
@@ -380,10 +384,14 @@ impl CollabPanel {
if !self.collapsed_sections.contains(&Section::ActiveCall) {
let room = room.read(cx);
+ let mut guest_count_ix = 0;
+ let mut guest_count = if room.read_only() { 1 } else { 0 };
+ let mut non_guest_count = if room.read_only() { 0 } else { 1 };
if let Some(channel_id) = room.channel_id() {
self.entries.push(ListEntry::ChannelNotes { channel_id });
- self.entries.push(ListEntry::ChannelChat { channel_id })
+ self.entries.push(ListEntry::ChannelChat { channel_id });
+ guest_count_ix = self.entries.len();
}
// Populate the active user.
@@ -402,7 +410,7 @@ impl CollabPanel {
&Default::default(),
executor.clone(),
));
- if !matches.is_empty() {
+ if !matches.is_empty() && !room.read_only() {
let user_id = user.id;
self.entries.push(ListEntry::CallParticipant {
user,
@@ -430,13 +438,23 @@ impl CollabPanel {
// Populate remote participants.
self.match_candidates.clear();
self.match_candidates
- .extend(room.remote_participants().iter().map(|(_, participant)| {
- StringMatchCandidate {
- id: participant.user.id as usize,
- string: participant.user.github_login.clone(),
- char_bag: participant.user.github_login.chars().collect(),
- }
- }));
+ .extend(
+ room.remote_participants()
+ .iter()
+ .filter_map(|(_, participant)| {
+ if participant.role == proto::ChannelRole::Guest {
+ guest_count += 1;
+ return None;
+ } else {
+ non_guest_count += 1;
+ }
+ Some(StringMatchCandidate {
+ id: participant.user.id as usize,
+ string: participant.user.github_login.clone(),
+ char_bag: participant.user.github_login.chars().collect(),
+ })
+ }),
+ );
let matches = executor.block(match_strings(
&self.match_candidates,
&query,
@@ -470,6 +488,15 @@ impl CollabPanel {
});
}
}
+ if guest_count > 0 {
+ self.entries.insert(
+ guest_count_ix,
+ ListEntry::GuestCount {
+ count: guest_count,
+ has_visible_participants: non_guest_count > 0,
+ },
+ );
+ }
// Populate pending participants.
self.match_candidates.clear();
@@ -959,6 +986,41 @@ impl CollabPanel {
.tooltip(move |cx| Tooltip::text("Open Chat", cx))
}
+ fn render_guest_count(
+ &self,
+ count: usize,
+ has_visible_participants: bool,
+ is_selected: bool,
+ cx: &mut ViewContext<Self>,
+ ) -> impl IntoElement {
+ let manageable_channel_id = ActiveCall::global(cx).read(cx).room().and_then(|room| {
+ let room = room.read(cx);
+ if room.local_participant_is_admin() {
+ room.channel_id()
+ } else {
+ None
+ }
+ });
+
+ ListItem::new("guest_count")
+ .selected(is_selected)
+ .start_slot(
+ h_stack()
+ .gap_1()
+ .child(render_tree_branch(!has_visible_participants, cx))
+ .child(""),
+ )
+ .child(Label::new(if count == 1 {
+ format!("{} guest", count)
+ } else {
+ format!("{} guests", count)
+ }))
+ .when_some(manageable_channel_id, |el, channel_id| {
+ el.tooltip(move |cx| Tooltip::text("Manage Members", cx))
+ .on_click(cx.listener(move |this, _, cx| this.manage_members(channel_id, cx)))
+ })
+ }
+
fn has_subchannels(&self, ix: usize) -> bool {
self.entries.get(ix).map_or(false, |entry| {
if let ListEntry::Channel { has_children, .. } = entry {
@@ -1180,6 +1242,18 @@ impl CollabPanel {
});
}
}
+ ListEntry::GuestCount { .. } => {
+ let Some(room) = ActiveCall::global(cx).read(cx).room() else {
+ return;
+ };
+ let room = room.read(cx);
+ let Some(channel_id) = room.channel_id() else {
+ return;
+ };
+ if room.local_participant_is_admin() {
+ self.manage_members(channel_id, cx)
+ }
+ }
ListEntry::Channel { channel, .. } => {
let is_active = maybe!({
let call_channel = ActiveCall::global(cx)
@@ -1735,6 +1809,12 @@ impl CollabPanel {
ListEntry::ParticipantScreen { peer_id, is_last } => self
.render_participant_screen(*peer_id, *is_last, is_selected, cx)
.into_any_element(),
+ ListEntry::GuestCount {
+ count,
+ has_visible_participants,
+ } => self
+ .render_guest_count(*count, *has_visible_participants, is_selected, cx)
+ .into_any_element(),
ListEntry::ChannelNotes { channel_id } => self
.render_channel_notes(*channel_id, is_selected, cx)
.into_any_element(),
@@ -1749,15 +1829,49 @@ impl CollabPanel {
.size_full()
.child(list(self.list_state.clone()).full())
.child(
- v_stack().p_2().child(
- v_stack()
- .border_primary(cx)
- .border_t()
- .child(self.filter_editor.clone()),
- ),
+ v_stack()
+ .child(div().mx_2().border_primary(cx).border_t())
+ .child(
+ v_stack()
+ .p_2()
+ .child(self.render_filter_input(&self.filter_editor, cx)),
+ ),
)
}
+ fn render_filter_input(
+ &self,
+ editor: &View<Editor>,
+ cx: &mut ViewContext<Self>,
+ ) -> impl IntoElement {
+ let settings = ThemeSettings::get_global(cx);
+ let text_style = TextStyle {
+ color: if editor.read(cx).read_only(cx) {
+ cx.theme().colors().text_disabled
+ } else {
+ cx.theme().colors().text
+ },
+ font_family: settings.ui_font.family.clone(),
+ font_features: settings.ui_font.features,
+ font_size: rems(0.875).into(),
+ font_weight: FontWeight::NORMAL,
+ font_style: FontStyle::Normal,
+ line_height: relative(1.3).into(),
+ background_color: None,
+ underline: None,
+ white_space: WhiteSpace::Normal,
+ };
+
+ EditorElement::new(
+ editor,
+ EditorStyle {
+ local_player: cx.theme().players().local(),
+ text: text_style,
+ ..Default::default()
+ },
+ )
+ }
+
fn render_header(
&self,
section: Section,
@@ -2504,6 +2618,11 @@ impl PartialEq for ListEntry {
return true;
}
}
+ ListEntry::GuestCount { .. } => {
+ if let ListEntry::GuestCount { .. } = other {
+ return true;
+ }
+ }
}
false
}
@@ -10,11 +10,12 @@ use gpui::{
};
use project::{Project, RepositoryEntry};
use recent_projects::RecentProjects;
+use rpc::proto;
use std::sync::Arc;
use theme::{ActiveTheme, PlayerColors};
use ui::{
h_stack, popover_menu, prelude::*, Avatar, Button, ButtonLike, ButtonStyle, ContextMenu, Icon,
- IconButton, IconElement, Tooltip,
+ IconButton, IconElement, TintColor, Tooltip,
};
use util::ResultExt;
use vcs_menu::{build_branch_list, BranchList, OpenRecent as ToggleVcsMenu};
@@ -175,14 +176,17 @@ impl Render for CollabTitlebarItem {
let is_muted = room.is_muted(cx);
let is_deafened = room.is_deafened().unwrap_or(false);
let is_screen_sharing = room.is_screen_sharing();
+ let read_only = room.read_only();
- this.when(is_local, |this| {
+ this.when(is_local && !read_only, |this| {
this.child(
Button::new(
"toggle_sharing",
if is_shared { "Unshare" } else { "Share" },
)
.style(ButtonStyle::Subtle)
+ .selected_style(ButtonStyle::Tinted(TintColor::Accent))
+ .selected(is_shared)
.label_size(LabelSize::Small)
.on_click(cx.listener(
move |this, _, cx| {
@@ -205,20 +209,23 @@ impl Render for CollabTitlebarItem {
.detach_and_log_err(cx);
}),
)
- .child(
- IconButton::new(
- "mute-microphone",
- if is_muted {
- ui::Icon::MicMute
- } else {
- ui::Icon::Mic
- },
+ .when(!read_only, |this| {
+ this.child(
+ IconButton::new(
+ "mute-microphone",
+ if is_muted {
+ ui::Icon::MicMute
+ } else {
+ ui::Icon::Mic
+ },
+ )
+ .style(ButtonStyle::Subtle)
+ .icon_size(IconSize::Small)
+ .selected(is_muted)
+ .selected_style(ButtonStyle::Tinted(TintColor::Negative))
+ .on_click(move |_, cx| crate::toggle_mute(&Default::default(), cx)),
)
- .style(ButtonStyle::Subtle)
- .icon_size(IconSize::Small)
- .selected(is_muted)
- .on_click(move |_, cx| crate::toggle_mute(&Default::default(), cx)),
- )
+ })
.child(
IconButton::new(
"mute-sound",
@@ -229,22 +236,35 @@ impl Render for CollabTitlebarItem {
},
)
.style(ButtonStyle::Subtle)
+ .selected_style(ButtonStyle::Tinted(TintColor::Negative))
.icon_size(IconSize::Small)
.selected(is_deafened)
.tooltip(move |cx| {
- Tooltip::with_meta("Deafen Audio", None, "Mic will be muted", cx)
+ if !read_only {
+ Tooltip::with_meta(
+ "Deafen Audio",
+ None,
+ "Mic will be muted",
+ cx,
+ )
+ } else {
+ Tooltip::text("Deafen Audio", cx)
+ }
})
- .on_click(move |_, cx| crate::toggle_mute(&Default::default(), cx)),
- )
- .child(
- IconButton::new("screen-share", ui::Icon::Screen)
- .style(ButtonStyle::Subtle)
- .icon_size(IconSize::Small)
- .selected(is_screen_sharing)
- .on_click(move |_, cx| {
- crate::toggle_screen_sharing(&Default::default(), cx)
- }),
+ .on_click(move |_, cx| crate::toggle_deafen(&Default::default(), cx)),
)
+ .when(!read_only, |this| {
+ this.child(
+ IconButton::new("screen-share", ui::Icon::Screen)
+ .style(ButtonStyle::Subtle)
+ .icon_size(IconSize::Small)
+ .selected(is_screen_sharing)
+ .selected_style(ButtonStyle::Tinted(TintColor::Accent))
+ .on_click(move |_, cx| {
+ crate::toggle_screen_sharing(&Default::default(), cx)
+ }),
+ )
+ })
})
.map(|el| {
let status = self.client.status();
@@ -409,6 +429,10 @@ impl CollabTitlebarItem {
current_user: &Arc<User>,
cx: &ViewContext<Self>,
) -> Option<FacePile> {
+ if room.role_for_user(user.id) == Some(proto::ChannelRole::Guest) {
+ return None;
+ }
+
let followers = project_id.map_or(&[] as &[_], |id| room.followers_for(peer_id, id));
let pile = FacePile::default()
@@ -370,6 +370,7 @@ mod tests {
use gpui::TestAppContext;
use language::Point;
use project::Project;
+ use settings::KeymapFile;
use workspace::{AppState, Workspace};
#[test]
@@ -503,7 +504,20 @@ mod tests {
workspace::init(app_state.clone(), cx);
init(cx);
Project::init_settings(cx);
- settings::load_default_keymap(cx);
+ KeymapFile::parse(
+ r#"[
+ {
+ "bindings": {
+ "cmd-n": "workspace::NewFile",
+ "enter": "menu::Confirm",
+ "cmd-shift-p": "command_palette::Toggle"
+ }
+ }
+ ]"#,
+ )
+ .unwrap()
+ .add_to_cx(cx)
+ .unwrap();
app_state
})
}
@@ -151,7 +151,12 @@ impl ProjectDiagnosticsEditor {
let focus_in_subscription =
cx.on_focus_in(&focus_handle, |diagnostics, cx| diagnostics.focus_in(cx));
- let excerpts = cx.new_model(|cx| MultiBuffer::new(project_handle.read(cx).replica_id()));
+ let excerpts = cx.new_model(|cx| {
+ MultiBuffer::new(
+ project_handle.read(cx).replica_id(),
+ project_handle.read(cx).capability(),
+ )
+ });
let editor = cx.new_view(|cx| {
let mut editor =
Editor::for_multibuffer(excerpts.clone(), Some(project_handle.clone()), cx);
@@ -641,8 +646,13 @@ impl Item for ProjectDiagnosticsEditor {
fn tab_content(&self, _detail: Option<usize>, selected: bool, _: &WindowContext) -> AnyElement {
if self.summary.error_count == 0 && self.summary.warning_count == 0 {
- let label = Label::new("No problems");
- label.into_any_element()
+ Label::new("No problems")
+ .color(if selected {
+ Color::Default
+ } else {
+ Color::Muted
+ })
+ .into_any_element()
} else {
h_stack()
.gap_1()
@@ -1567,6 +1577,7 @@ mod tests {
workspace::init_settings(cx);
Project::init_settings(cx);
crate::init(cx);
+ editor::init(cx);
});
}
@@ -54,10 +54,10 @@ use itertools::Itertools;
pub use language::{char_kind, CharKind};
use language::{
language_settings::{self, all_language_settings, InlayHintSettings},
- markdown, point_from_lsp, AutoindentMode, BracketPair, Buffer, CodeAction, CodeLabel,
- Completion, CursorShape, Diagnostic, Documentation, IndentKind, IndentSize, Language,
- LanguageRegistry, LanguageServerName, OffsetRangeExt, Point, Selection, SelectionGoal,
- TransactionId,
+ markdown, point_from_lsp, AutoindentMode, BracketPair, Buffer, Capability, CodeAction,
+ CodeLabel, Completion, CursorShape, Diagnostic, Documentation, IndentKind, IndentSize,
+ Language, LanguageRegistry, LanguageServerName, OffsetRangeExt, Point, Selection,
+ SelectionGoal, TransactionId,
};
use link_go_to_definition::{GoToDefinitionLink, InlayHighlight, LinkGoToDefinitionState};
@@ -2049,8 +2049,8 @@ impl Editor {
}
}
- pub fn read_only(&self) -> bool {
- self.read_only
+ pub fn read_only(&self, cx: &AppContext) -> bool {
+ self.read_only || self.buffer.read(cx).read_only()
}
pub fn set_read_only(&mut self, read_only: bool) {
@@ -2199,7 +2199,7 @@ impl Editor {
S: ToOffset,
T: Into<Arc<str>>,
{
- if self.read_only {
+ if self.read_only(cx) {
return;
}
@@ -2213,7 +2213,7 @@ impl Editor {
S: ToOffset,
T: Into<Arc<str>>,
{
- if self.read_only {
+ if self.read_only(cx) {
return;
}
@@ -2232,7 +2232,7 @@ impl Editor {
S: ToOffset,
T: Into<Arc<str>>,
{
- if self.read_only {
+ if self.read_only(cx) {
return;
}
@@ -2596,7 +2596,7 @@ impl Editor {
pub fn handle_input(&mut self, text: &str, cx: &mut ViewContext<Self>) {
let text: Arc<str> = text.into();
- if self.read_only {
+ if self.read_only(cx) {
return;
}
@@ -3049,7 +3049,7 @@ impl Editor {
autoindent_mode: Option<AutoindentMode>,
cx: &mut ViewContext<Self>,
) {
- if self.read_only {
+ if self.read_only(cx) {
return;
}
@@ -3786,7 +3786,8 @@ impl Editor {
let mut ranges_to_highlight = Vec::new();
let excerpt_buffer = cx.new_model(|cx| {
- let mut multibuffer = MultiBuffer::new(replica_id).with_title(title);
+ let mut multibuffer =
+ MultiBuffer::new(replica_id, Capability::ReadWrite).with_title(title);
for (buffer_handle, transaction) in &entries {
let buffer = buffer_handle.read(cx);
ranges_to_highlight.extend(
@@ -7491,9 +7492,10 @@ impl Editor {
locations.sort_by_key(|location| location.buffer.read(cx).remote_id());
let mut locations = locations.into_iter().peekable();
let mut ranges_to_highlight = Vec::new();
+ let capability = workspace.project().read(cx).capability();
let excerpt_buffer = cx.new_model(|cx| {
- let mut multibuffer = MultiBuffer::new(replica_id);
+ let mut multibuffer = MultiBuffer::new(replica_id, capability);
while let Some(location) = locations.next() {
let buffer = location.buffer.read(cx);
let mut ranges_for_buffer = Vec::new();
@@ -8608,7 +8610,8 @@ impl Editor {
}
pub fn show_local_cursors(&self, cx: &WindowContext) -> bool {
- self.blink_manager.read(cx).visible() && self.focus_handle.is_focused(cx)
+ (self.read_only(cx) || self.blink_manager.read(cx).visible())
+ && self.focus_handle.is_focused(cx)
}
fn on_buffer_changed(&mut self, _: Model<MultiBuffer>, cx: &mut ViewContext<Self>) {
@@ -9565,7 +9568,7 @@ impl InputHandler for Editor {
) -> Option<gpui::Bounds<Pixels>> {
let text_layout_details = self.text_layout_details(cx);
let style = &text_layout_details.editor_style;
- let font_id = cx.text_system().font_id(&style.text.font()).unwrap();
+ let font_id = cx.text_system().resolve_font(&style.text.font());
let font_size = style.text.font_size.to_pixels(cx.rem_size());
let line_height = style.text.line_height_in_pixels(cx.rem_size());
let em_width = cx
@@ -17,8 +17,9 @@ use gpui::{
use indoc::indoc;
use language::{
language_settings::{AllLanguageSettings, AllLanguageSettingsContent, LanguageSettingsContent},
- BracketPairConfig, FakeLspAdapter, LanguageConfig, LanguageConfigOverride, LanguageRegistry,
- Override, Point,
+ BracketPairConfig,
+ Capability::ReadWrite,
+ FakeLspAdapter, LanguageConfig, LanguageConfigOverride, LanguageRegistry, Override, Point,
};
use parking_lot::Mutex;
use project::project_settings::{LspSettings, ProjectSettings};
@@ -2355,7 +2356,7 @@ fn test_indent_outdent_with_excerpts(cx: &mut TestAppContext) {
.with_language(rust_language, cx)
});
let multibuffer = cx.new_model(|cx| {
- let mut multibuffer = MultiBuffer::new(0);
+ let mut multibuffer = MultiBuffer::new(0, ReadWrite);
multibuffer.push_excerpts(
toml_buffer.clone(),
[ExcerptRange {
@@ -6019,7 +6020,7 @@ fn test_editing_disjoint_excerpts(cx: &mut TestAppContext) {
let buffer = cx.new_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), sample_text(3, 4, 'a')));
let multibuffer = cx.new_model(|cx| {
- let mut multibuffer = MultiBuffer::new(0);
+ let mut multibuffer = MultiBuffer::new(0, ReadWrite);
multibuffer.push_excerpts(
buffer.clone(),
[
@@ -6103,7 +6104,7 @@ fn test_editing_overlapping_excerpts(cx: &mut TestAppContext) {
});
let buffer = cx.new_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), initial_text));
let multibuffer = cx.new_model(|cx| {
- let mut multibuffer = MultiBuffer::new(0);
+ let mut multibuffer = MultiBuffer::new(0, ReadWrite);
multibuffer.push_excerpts(buffer, excerpt_ranges, cx);
multibuffer
});
@@ -6162,7 +6163,7 @@ fn test_refresh_selections(cx: &mut TestAppContext) {
let buffer = cx.new_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), sample_text(3, 4, 'a')));
let mut excerpt1_id = None;
let multibuffer = cx.new_model(|cx| {
- let mut multibuffer = MultiBuffer::new(0);
+ let mut multibuffer = MultiBuffer::new(0, ReadWrite);
excerpt1_id = multibuffer
.push_excerpts(
buffer.clone(),
@@ -6247,7 +6248,7 @@ fn test_refresh_selections_while_selecting_with_mouse(cx: &mut TestAppContext) {
let buffer = cx.new_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), sample_text(3, 4, 'a')));
let mut excerpt1_id = None;
let multibuffer = cx.new_model(|cx| {
- let mut multibuffer = MultiBuffer::new(0);
+ let mut multibuffer = MultiBuffer::new(0, ReadWrite);
excerpt1_id = multibuffer
.push_excerpts(
buffer.clone(),
@@ -6636,7 +6637,7 @@ async fn test_following_with_multiple_excerpts(cx: &mut gpui::TestAppContext) {
let cx = &mut VisualTestContext::from_window(*workspace.deref(), cx);
let leader = pane.update(cx, |_, cx| {
- let multibuffer = cx.new_model(|_| MultiBuffer::new(0));
+ let multibuffer = cx.new_model(|_| MultiBuffer::new(0, ReadWrite));
cx.new_view(|cx| build_editor(multibuffer.clone(), cx))
});
@@ -7425,7 +7426,7 @@ async fn test_copilot_multibuffer(executor: BackgroundExecutor, cx: &mut gpui::T
let buffer_1 = cx.new_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), "a = 1\nb = 2\n"));
let buffer_2 = cx.new_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), "c = 3\nd = 4\n"));
let multibuffer = cx.new_model(|cx| {
- let mut multibuffer = MultiBuffer::new(0);
+ let mut multibuffer = MultiBuffer::new(0, ReadWrite);
multibuffer.push_excerpts(
buffer_1.clone(),
[ExcerptRange {
@@ -7552,7 +7553,7 @@ async fn test_copilot_disabled_globs(executor: BackgroundExecutor, cx: &mut gpui
.unwrap();
let multibuffer = cx.new_model(|cx| {
- let mut multibuffer = MultiBuffer::new(0);
+ let mut multibuffer = MultiBuffer::new(0, ReadWrite);
multibuffer.push_excerpts(
private_buffer.clone(),
[ExcerptRange {
@@ -1230,6 +1230,14 @@ impl EditorElement {
return;
}
+ // If a drag took place after we started dragging the scrollbar,
+ // cancel the scrollbar drag.
+ if cx.has_active_drag() {
+ self.editor.update(cx, |editor, cx| {
+ editor.scroll_manager.set_is_dragging_scrollbar(false, cx);
+ });
+ }
+
let top = bounds.origin.y;
let bottom = bounds.lower_left().y;
let right = bounds.lower_right().x;
@@ -1767,7 +1775,7 @@ impl EditorElement {
let snapshot = editor.snapshot(cx);
let style = self.style.clone();
- let font_id = cx.text_system().font_id(&style.text.font()).unwrap();
+ let font_id = cx.text_system().resolve_font(&style.text.font());
let font_size = style.text.font_size.to_pixels(cx.rem_size());
let line_height = style.text.line_height_in_pixels(cx.rem_size());
let em_width = cx
@@ -1902,7 +1910,13 @@ impl EditorElement {
layouts.push(layout);
}
- selections.push((style.local_player, layouts));
+ let player = if editor.read_only(cx) {
+ cx.theme().players().read_only()
+ } else {
+ style.local_player
+ };
+
+ selections.push((player, layouts));
}
if let Some(collaboration_hub) = &editor.collaboration_hub {
@@ -3774,7 +3788,7 @@ fn compute_auto_height_layout(
}
let style = editor.style.as_ref().unwrap();
- let font_id = cx.text_system().font_id(&style.text.font()).unwrap();
+ let font_id = cx.text_system().resolve_font(&style.text.font());
let font_size = style.text.font_size.to_pixels(cx.rem_size());
let line_height = style.text.line_height_in_pixels(cx.rem_size());
let em_width = cx
@@ -93,6 +93,7 @@ mod tests {
use crate::editor_tests::init_test;
use crate::Point;
use gpui::{Context, TestAppContext};
+ use language::Capability::ReadWrite;
use multi_buffer::{ExcerptRange, MultiBuffer};
use project::{FakeFs, Project};
use unindent::Unindent;
@@ -183,7 +184,7 @@ mod tests {
cx.background_executor.run_until_parked();
let multibuffer = cx.new_model(|cx| {
- let mut multibuffer = MultiBuffer::new(0);
+ let mut multibuffer = MultiBuffer::new(0, ReadWrite);
multibuffer.push_excerpts(
buffer_1.clone(),
[
@@ -1206,7 +1206,8 @@ pub mod tests {
use gpui::{Context, TestAppContext, WindowHandle};
use itertools::Itertools;
use language::{
- language_settings::AllLanguageSettingsContent, FakeLspAdapter, Language, LanguageConfig,
+ language_settings::AllLanguageSettingsContent, Capability, FakeLspAdapter, Language,
+ LanguageConfig,
};
use lsp::FakeLanguageServer;
use parking_lot::Mutex;
@@ -2459,7 +2460,7 @@ pub mod tests {
.await
.unwrap();
let multibuffer = cx.new_model(|cx| {
- let mut multibuffer = MultiBuffer::new(0);
+ let mut multibuffer = MultiBuffer::new(0, Capability::ReadWrite);
multibuffer.push_excerpts(
buffer_1.clone(),
[
@@ -2798,7 +2799,7 @@ pub mod tests {
})
.await
.unwrap();
- let multibuffer = cx.new_model(|_| MultiBuffer::new(0));
+ let multibuffer = cx.new_model(|_| MultiBuffer::new(0, Capability::ReadWrite));
let (buffer_1_excerpts, buffer_2_excerpts) = multibuffer.update(cx, |multibuffer, cx| {
let buffer_1_excerpts = multibuffer.push_excerpts(
buffer_1.clone(),
@@ -15,9 +15,11 @@ use language::{
proto::serialize_anchor as serialize_text_anchor, Bias, Buffer, CharKind, OffsetRangeExt,
Point, SelectionGoal,
};
+use project::repository::GitFileStatus;
use project::{search::SearchQuery, FormatTrigger, Item as _, Project, ProjectPath};
use rpc::proto::{self, update_view, PeerId};
use settings::Settings;
+use workspace::item::ItemSettings;
use std::fmt::Write;
use std::{
@@ -29,7 +31,7 @@ use std::{
sync::Arc,
};
use text::Selection;
-use theme::{ActiveTheme, Theme};
+use theme::Theme;
use ui::{h_stack, prelude::*, Label};
use util::{paths::PathExt, paths::FILE_ROW_COLUMN_DELIMITER, ResultExt, TryFutureExt};
use workspace::{
@@ -101,7 +103,8 @@ impl FollowableItem for Editor {
if state.singleton && buffers.len() == 1 {
multibuffer = MultiBuffer::singleton(buffers.pop().unwrap(), cx)
} else {
- multibuffer = MultiBuffer::new(replica_id);
+ multibuffer =
+ MultiBuffer::new(replica_id, project.read(cx).capability());
let mut excerpts = state.excerpts.into_iter().peekable();
while let Some(excerpt) = excerpts.peek() {
let buffer_id = excerpt.buffer_id;
@@ -579,7 +582,28 @@ impl Item for Editor {
}
fn tab_content(&self, detail: Option<usize>, selected: bool, cx: &WindowContext) -> AnyElement {
- let _theme = cx.theme();
+ let git_status = if ItemSettings::get_global(cx).git_status {
+ self.buffer()
+ .read(cx)
+ .as_singleton()
+ .and_then(|buffer| buffer.read(cx).project_path(cx))
+ .and_then(|path| self.project.as_ref()?.read(cx).entry_for_path(&path, cx))
+ .and_then(|entry| entry.git_status())
+ } else {
+ None
+ };
+ let label_color = match git_status {
+ Some(GitFileStatus::Added) => Color::Created,
+ Some(GitFileStatus::Modified) => Color::Modified,
+ Some(GitFileStatus::Conflict) => Color::Conflict,
+ None => {
+ if selected {
+ Color::Default
+ } else {
+ Color::Muted
+ }
+ }
+ };
let description = detail.and_then(|detail| {
let path = path_for_buffer(&self.buffer, detail, false, cx)?;
@@ -595,11 +619,7 @@ impl Item for Editor {
h_stack()
.gap_2()
- .child(Label::new(self.title(cx).to_string()).color(if selected {
- Color::Default
- } else {
- Color::Muted
- }))
+ .child(Label::new(self.title(cx).to_string()).color(label_color))
.when_some(description, |this, description| {
this.child(
Label::new(description)
@@ -930,10 +930,7 @@ mod tests {
fn do_work() { «test»(); }
"});
- // Deactivating the window dismisses the highlight
- cx.update_workspace(|workspace, cx| {
- workspace.on_window_activation_changed(cx);
- });
+ cx.cx.cx.deactivate_window();
cx.assert_editor_text_highlights::<LinkGoToDefinitionState>(indoc! {"
fn test() { do_work(); }
fn do_work() { test(); }
@@ -461,6 +461,7 @@ mod tests {
Buffer, DisplayMap, ExcerptRange, InlayId, MultiBuffer,
};
use gpui::{font, Context as _};
+ use language::Capability;
use project::Project;
use settings::SettingsStore;
use util::post_inc;
@@ -766,7 +767,7 @@ mod tests {
let buffer =
cx.new_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), "abc\ndefg\nhijkl\nmn"));
let multibuffer = cx.new_model(|cx| {
- let mut multibuffer = MultiBuffer::new(0);
+ let mut multibuffer = MultiBuffer::new(0, Capability::ReadWrite);
multibuffer.push_excerpts(
buffer.clone(),
[
@@ -18,7 +18,6 @@ gpui = { path = "../gpui" }
language = { path = "../language" }
menu = { path = "../menu" }
project = { path = "../project" }
-search = { path = "../search" }
settings = { path = "../settings" }
theme = { path = "../theme" }
ui = { path = "../ui" }
@@ -18,8 +18,7 @@ collections = { path = "../collections" }
gpui_macros = { path = "../gpui_macros" }
util = { path = "../util" }
sum_tree = { path = "../sum_tree" }
-sqlez = { path = "../sqlez" }
-async-task = "4.0.3"
+async-task = "4.7"
backtrace = { version = "0.3", optional = true }
ctor.workspace = true
linkme = "0.3"
@@ -327,6 +327,7 @@ impl AppContext {
pub fn refresh(&mut self) {
self.pending_effects.push_back(Effect::Refresh);
}
+
pub(crate) fn update<R>(&mut self, update: impl FnOnce(&mut Self) -> R) -> R {
self.pending_updates += 1;
let result = update(self);
@@ -840,10 +841,12 @@ impl AppContext {
/// Update the global of the given type with a closure. Unlike `global_mut`, this method provides
/// your closure with mutable access to the `AppContext` and the global simultaneously.
pub fn update_global<G: 'static, R>(&mut self, f: impl FnOnce(&mut G, &mut Self) -> R) -> R {
- let mut global = self.lease_global::<G>();
- let result = f(&mut global, self);
- self.end_global_lease(global);
- result
+ self.update(|cx| {
+ let mut global = cx.lease_global::<G>();
+ let result = f(&mut global, cx);
+ cx.end_global_lease(global);
+ result
+ })
}
/// Register a callback to be invoked when a global of the given type is updated.
@@ -941,6 +944,11 @@ impl AppContext {
self.pending_effects.push_back(Effect::Refresh);
}
+ pub fn clear_key_bindings(&mut self) {
+ self.keymap.lock().clear();
+ self.pending_effects.push_back(Effect::Refresh);
+ }
+
/// Register a global listener for actions invoked via the keyboard.
pub fn on_action<A: Action>(&mut self, listener: impl Fn(&A, &mut Self) + 'static) {
self.global_action_listeners
@@ -16,6 +16,9 @@ use std::{
thread::panicking,
};
+#[cfg(any(test, feature = "test-support"))]
+use collections::HashMap;
+
slotmap::new_key_type! { pub struct EntityId; }
impl EntityId {
@@ -38,6 +41,8 @@ pub(crate) struct EntityMap {
struct EntityRefCounts {
counts: SlotMap<EntityId, AtomicUsize>,
dropped_entity_ids: Vec<EntityId>,
+ #[cfg(any(test, feature = "test-support"))]
+ leak_detector: LeakDetector,
}
impl EntityMap {
@@ -47,6 +52,11 @@ impl EntityMap {
ref_counts: Arc::new(RwLock::new(EntityRefCounts {
counts: SlotMap::with_key(),
dropped_entity_ids: Vec::new(),
+ #[cfg(any(test, feature = "test-support"))]
+ leak_detector: LeakDetector {
+ next_handle_id: 0,
+ entity_handles: HashMap::default(),
+ },
})),
}
}
@@ -156,6 +166,8 @@ pub struct AnyModel {
pub(crate) entity_id: EntityId,
pub(crate) entity_type: TypeId,
entity_map: Weak<RwLock<EntityRefCounts>>,
+ #[cfg(any(test, feature = "test-support"))]
+ handle_id: HandleId,
}
impl AnyModel {
@@ -163,7 +175,14 @@ impl AnyModel {
Self {
entity_id: id,
entity_type,
- entity_map,
+ entity_map: entity_map.clone(),
+ #[cfg(any(test, feature = "test-support"))]
+ handle_id: entity_map
+ .upgrade()
+ .unwrap()
+ .write()
+ .leak_detector
+ .handle_created(id),
}
}
@@ -207,11 +226,20 @@ impl Clone for AnyModel {
assert_ne!(prev_count, 0, "Detected over-release of a model.");
}
- Self {
+ let this = Self {
entity_id: self.entity_id,
entity_type: self.entity_type,
entity_map: self.entity_map.clone(),
- }
+ #[cfg(any(test, feature = "test-support"))]
+ handle_id: self
+ .entity_map
+ .upgrade()
+ .unwrap()
+ .write()
+ .leak_detector
+ .handle_created(self.entity_id),
+ };
+ this
}
}
@@ -231,6 +259,14 @@ impl Drop for AnyModel {
entity_map.dropped_entity_ids.push(self.entity_id);
}
}
+
+ #[cfg(any(test, feature = "test-support"))]
+ if let Some(entity_map) = self.entity_map.upgrade() {
+ entity_map
+ .write()
+ .leak_detector
+ .handle_dropped(self.entity_id, self.handle_id)
+ }
}
}
@@ -423,13 +459,43 @@ impl AnyWeakModel {
return None;
}
ref_count.fetch_add(1, SeqCst);
+ drop(ref_counts);
Some(AnyModel {
entity_id: self.entity_id,
entity_type: self.entity_type,
entity_map: self.entity_ref_counts.clone(),
+ #[cfg(any(test, feature = "test-support"))]
+ handle_id: self
+ .entity_ref_counts
+ .upgrade()
+ .unwrap()
+ .write()
+ .leak_detector
+ .handle_created(self.entity_id),
})
}
+
+ #[cfg(any(test, feature = "test-support"))]
+ pub fn assert_dropped(&self) {
+ self.entity_ref_counts
+ .upgrade()
+ .unwrap()
+ .write()
+ .leak_detector
+ .assert_dropped(self.entity_id);
+
+ if self
+ .entity_ref_counts
+ .upgrade()
+ .and_then(|ref_counts| Some(ref_counts.read().counts.get(self.entity_id)?.load(SeqCst)))
+ .is_some()
+ {
+ panic!(
+ "entity was recently dropped but resources are retained until the end of the effect cycle."
+ )
+ }
+ }
}
impl<T> From<WeakModel<T>> for AnyWeakModel {
@@ -534,6 +600,59 @@ impl<T> PartialEq<Model<T>> for WeakModel<T> {
}
}
+#[cfg(any(test, feature = "test-support"))]
+lazy_static::lazy_static! {
+ static ref LEAK_BACKTRACE: bool =
+ std::env::var("LEAK_BACKTRACE").map_or(false, |b| !b.is_empty());
+}
+
+#[cfg(any(test, feature = "test-support"))]
+#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq)]
+pub struct HandleId {
+ id: u64, // id of the handle itself, not the pointed at object
+}
+
+#[cfg(any(test, feature = "test-support"))]
+pub struct LeakDetector {
+ next_handle_id: u64,
+ entity_handles: HashMap<EntityId, HashMap<HandleId, Option<backtrace::Backtrace>>>,
+}
+
+#[cfg(any(test, feature = "test-support"))]
+impl LeakDetector {
+ #[track_caller]
+ pub fn handle_created(&mut self, entity_id: EntityId) -> HandleId {
+ let id = util::post_inc(&mut self.next_handle_id);
+ let handle_id = HandleId { id };
+ let handles = self.entity_handles.entry(entity_id).or_default();
+ handles.insert(
+ handle_id,
+ LEAK_BACKTRACE.then(|| backtrace::Backtrace::new_unresolved()),
+ );
+ handle_id
+ }
+
+ pub fn handle_dropped(&mut self, entity_id: EntityId, handle_id: HandleId) {
+ let handles = self.entity_handles.entry(entity_id).or_default();
+ handles.remove(&handle_id);
+ }
+
+ pub fn assert_dropped(&mut self, entity_id: EntityId) {
+ let handles = self.entity_handles.entry(entity_id).or_default();
+ if !handles.is_empty() {
+ for (_, backtrace) in handles {
+ if let Some(mut backtrace) = backtrace.take() {
+ backtrace.resolve();
+ eprintln!("Leaked handle: {:#?}", backtrace);
+ } else {
+ eprintln!("Leaked handle: export LEAK_BACKTRACE to find allocation site");
+ }
+ }
+ panic!();
+ }
+ }
+}
+
#[cfg(test)]
mod test {
use crate::EntityMap;
@@ -1,14 +1,13 @@
use crate::{
div, Action, AnyView, AnyWindowHandle, AppCell, AppContext, AsyncAppContext,
- BackgroundExecutor, Bounds, ClipboardItem, Context, Entity, EventEmitter, ForegroundExecutor,
- InputEvent, IntoElement, KeyDownEvent, Keystroke, Model, ModelContext, Pixels, Platform,
- PlatformWindow, Point, Render, Result, Size, Task, TestDispatcher, TestPlatform, TestWindow,
- TestWindowHandlers, TextSystem, View, ViewContext, VisualContext, WindowBounds, WindowContext,
- WindowHandle, WindowOptions,
+ BackgroundExecutor, ClipboardItem, Context, Entity, EventEmitter, ForegroundExecutor,
+ IntoElement, Keystroke, Model, ModelContext, Pixels, Platform, Render, Result, Size, Task,
+ TestDispatcher, TestPlatform, TestWindow, TextSystem, View, ViewContext, VisualContext,
+ WindowContext, WindowHandle, WindowOptions,
};
use anyhow::{anyhow, bail};
use futures::{Stream, StreamExt};
-use std::{future::Future, mem, ops::Deref, rc::Rc, sync::Arc, time::Duration};
+use std::{future::Future, ops::Deref, rc::Rc, sync::Arc, time::Duration};
#[derive(Clone)]
pub struct TestAppContext {
@@ -185,42 +184,7 @@ impl TestAppContext {
}
pub fn simulate_window_resize(&self, window_handle: AnyWindowHandle, size: Size<Pixels>) {
- let (mut handlers, scale_factor) = self
- .app
- .borrow_mut()
- .update_window(window_handle, |_, cx| {
- let platform_window = cx.window.platform_window.as_test().unwrap();
- let scale_factor = platform_window.scale_factor();
- match &mut platform_window.bounds {
- WindowBounds::Fullscreen | WindowBounds::Maximized => {
- platform_window.bounds = WindowBounds::Fixed(Bounds {
- origin: Point::default(),
- size: size.map(|pixels| f64::from(pixels).into()),
- });
- }
- WindowBounds::Fixed(bounds) => {
- bounds.size = size.map(|pixels| f64::from(pixels).into());
- }
- }
-
- (
- mem::take(&mut platform_window.handlers.lock().resize),
- scale_factor,
- )
- })
- .unwrap();
-
- for handler in &mut handlers {
- handler(size, scale_factor);
- }
-
- self.app
- .borrow_mut()
- .update_window(window_handle, |_, cx| {
- let platform_window = cx.window.platform_window.as_test().unwrap();
- platform_window.handlers.lock().resize = handlers;
- })
- .unwrap();
+ self.test_window(window_handle).simulate_resize(size);
}
pub fn spawn<Fut, R>(&self, f: impl FnOnce(AsyncAppContext) -> Fut) -> Task<R>
@@ -313,41 +277,22 @@ impl TestAppContext {
keystroke: Keystroke,
is_held: bool,
) {
- let keystroke2 = keystroke.clone();
- let handled = window
- .update(self, |_, cx| {
- cx.dispatch_event(InputEvent::KeyDown(KeyDownEvent { keystroke, is_held }))
- })
- .is_ok_and(|handled| handled);
- if handled {
- return;
- }
-
- let input_handler = self.update_test_window(window, |window| window.input_handler.clone());
- let Some(input_handler) = input_handler else {
- panic!(
- "dispatch_keystroke {:?} failed to dispatch action or input",
- &keystroke2
- );
- };
- let text = keystroke2.ime_key.unwrap_or(keystroke2.key);
- input_handler.lock().replace_text_in_range(None, &text);
+ self.test_window(window)
+ .simulate_keystroke(keystroke, is_held)
}
- pub fn update_test_window<R>(
- &mut self,
- window: AnyWindowHandle,
- f: impl FnOnce(&mut TestWindow) -> R,
- ) -> R {
- window
- .update(self, |_, cx| {
- f(cx.window
- .platform_window
- .as_any_mut()
- .downcast_mut::<TestWindow>()
- .unwrap())
- })
+ pub fn test_window(&self, window: AnyWindowHandle) -> TestWindow {
+ self.app
+ .borrow_mut()
+ .windows
+ .get_mut(window.id)
+ .unwrap()
+ .as_mut()
.unwrap()
+ .platform_window
+ .as_test()
+ .unwrap()
+ .clone()
}
pub fn notifications<T: 'static>(&mut self, entity: &impl Entity<T>) -> impl Stream<Item = ()> {
@@ -563,11 +508,7 @@ impl<'a> VisualTestContext<'a> {
}
pub fn window_title(&mut self) -> Option<String> {
- self.cx
- .update_window(self.window, |_, cx| {
- cx.window.platform_window.as_test().unwrap().title.clone()
- })
- .unwrap()
+ self.cx.test_window(self.window).0.lock().title.clone()
}
pub fn simulate_keystrokes(&mut self, keystrokes: &str) {
@@ -578,37 +519,11 @@ impl<'a> VisualTestContext<'a> {
self.cx.simulate_input(self.window, input)
}
- pub fn simulate_activation(&mut self) {
- self.simulate_window_events(&mut |handlers| {
- handlers
- .active_status_change
- .iter_mut()
- .for_each(|f| f(true));
- })
- }
-
- pub fn simulate_deactivation(&mut self) {
- self.simulate_window_events(&mut |handlers| {
- handlers
- .active_status_change
- .iter_mut()
- .for_each(|f| f(false));
- })
- }
-
- fn simulate_window_events(&mut self, f: &mut dyn FnMut(&mut TestWindowHandlers)) {
- let handlers = self
- .cx
- .update_window(self.window, |_, cx| {
- cx.window
- .platform_window
- .as_test()
- .unwrap()
- .handlers
- .clone()
- })
- .unwrap();
- f(&mut *handlers.lock());
+ pub fn deactivate_window(&mut self) {
+ if Some(self.window) == self.test_platform.active_window() {
+ self.test_platform.set_active_window(None)
+ }
+ self.background_executor.run_until_parked();
}
}
@@ -339,6 +339,15 @@ impl Hsla {
}
}
+ pub fn grayscale(&self) -> Self {
+ Hsla {
+ h: self.h,
+ s: 0.,
+ l: self.l,
+ a: self.a,
+ }
+ }
+
/// Fade out the color by a given factor. This factor should be between 0.0 and 1.0.
/// Where 0.0 will leave the color unchanged, and 1.0 will completely fade out the color.
pub fn fade_out(&mut self, factor: f32) {
@@ -44,8 +44,9 @@ pub trait IntoElement: Sized {
}
/// Convert into an element, then draw in the current window at the given origin.
- /// The provided available space is provided to the layout engine to determine the size of the root element.
- /// Once the element is drawn, its associated element staet is yielded to the given callback.
+ /// The available space argument is provided to the layout engine to determine the size of the
+ // root element. Once the element is drawn, its associated element state is yielded to the
+ // given callback.
fn draw_and_update_state<T, R>(
self,
origin: Point<Pixels>,
@@ -31,39 +31,6 @@ pub trait Along {
fn apply_along(&self, axis: Axis, f: impl FnOnce(Self::Unit) -> Self::Unit) -> Self;
}
-impl sqlez::bindable::StaticColumnCount for Axis {}
-impl sqlez::bindable::Bind for Axis {
- fn bind(
- &self,
- statement: &sqlez::statement::Statement,
- start_index: i32,
- ) -> anyhow::Result<i32> {
- match self {
- Axis::Horizontal => "Horizontal",
- Axis::Vertical => "Vertical",
- }
- .bind(statement, start_index)
- }
-}
-
-impl sqlez::bindable::Column for Axis {
- fn column(
- statement: &mut sqlez::statement::Statement,
- start_index: i32,
- ) -> anyhow::Result<(Self, i32)> {
- String::column(statement, start_index).and_then(|(axis_text, next_index)| {
- Ok((
- match axis_text.as_str() {
- "Horizontal" => Axis::Horizontal,
- "Vertical" => Axis::Vertical,
- _ => anyhow::bail!("Stored serialized item kind is incorrect"),
- },
- next_index,
- ))
- })
- }
-}
-
/// Describes a location in a 2D cartesian coordinate space.
///
/// It holds two public fields, `x` and `y`, which represent the coordinates in the space.
@@ -2296,18 +2263,6 @@ impl From<f64> for GlobalPixels {
}
}
-impl sqlez::bindable::StaticColumnCount for GlobalPixels {}
-
-impl sqlez::bindable::Bind for GlobalPixels {
- fn bind(
- &self,
- statement: &sqlez::statement::Statement,
- start_index: i32,
- ) -> anyhow::Result<i32> {
- self.0.bind(statement, start_index)
- }
-}
-
/// Represents a length in rems, a unit based on the font-size of the window, which can be assigned with [WindowContext::set_rem_size].
///
/// Rems are used for defining lengths that are scalable and consistent across different UI elements.
@@ -307,7 +307,10 @@ mod test {
div().id("testview").child(
div()
.key_context("parent")
- .on_key_down(cx.listener(|this, _, _| this.saw_key_down = true))
+ .on_key_down(cx.listener(|this, _, cx| {
+ cx.stop_propagation();
+ this.saw_key_down = true
+ }))
.on_action(
cx.listener(|this: &mut TestView, _: &TestAction, _| {
this.saw_action = true
@@ -343,6 +346,7 @@ mod test {
.update(cx, |test_view, cx| cx.focus(&test_view.focus_handle))
.unwrap();
+ cx.dispatch_keystroke(*window, Keystroke::parse("a").unwrap(), false);
cx.dispatch_keystroke(*window, Keystroke::parse("ctrl-g").unwrap(), false);
window
@@ -6,19 +6,17 @@ mod mac;
mod test;
use crate::{
- point, size, Action, AnyWindowHandle, BackgroundExecutor, Bounds, DevicePixels, Font, FontId,
- FontMetrics, FontRun, ForegroundExecutor, GlobalPixels, GlyphId, InputEvent, Keymap,
- LineLayout, Pixels, Point, RenderGlyphParams, RenderImageParams, RenderSvgParams, Result,
- Scene, SharedString, Size, TaskLabel,
+ Action, AnyWindowHandle, BackgroundExecutor, Bounds, DevicePixels, Font, FontId, FontMetrics,
+ FontRun, ForegroundExecutor, GlobalPixels, GlyphId, InputEvent, Keymap, LineLayout, Pixels,
+ Point, RenderGlyphParams, RenderImageParams, RenderSvgParams, Result, Scene, SharedString,
+ Size, TaskLabel,
};
-use anyhow::{anyhow, bail};
+use anyhow::anyhow;
use async_task::Runnable;
use futures::channel::oneshot;
use parking::Unparker;
use seahash::SeaHasher;
use serde::{Deserialize, Serialize};
-use sqlez::bindable::{Bind, Column, StaticColumnCount};
-use sqlez::statement::Statement;
use std::borrow::Cow;
use std::hash::{Hash, Hasher};
use std::time::Duration;
@@ -396,67 +394,6 @@ pub enum WindowBounds {
Fixed(Bounds<GlobalPixels>),
}
-impl StaticColumnCount for WindowBounds {
- fn column_count() -> usize {
- 5
- }
-}
-
-impl Bind for WindowBounds {
- fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> {
- let (region, next_index) = match self {
- WindowBounds::Fullscreen => {
- let next_index = statement.bind(&"Fullscreen", start_index)?;
- (None, next_index)
- }
- WindowBounds::Maximized => {
- let next_index = statement.bind(&"Maximized", start_index)?;
- (None, next_index)
- }
- WindowBounds::Fixed(region) => {
- let next_index = statement.bind(&"Fixed", start_index)?;
- (Some(*region), next_index)
- }
- };
-
- statement.bind(
- ®ion.map(|region| {
- (
- region.origin.x,
- region.origin.y,
- region.size.width,
- region.size.height,
- )
- }),
- next_index,
- )
- }
-}
-
-impl Column for WindowBounds {
- fn column(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> {
- let (window_state, next_index) = String::column(statement, start_index)?;
- let bounds = match window_state.as_str() {
- "Fullscreen" => WindowBounds::Fullscreen,
- "Maximized" => WindowBounds::Maximized,
- "Fixed" => {
- let ((x, y, width, height), _) = Column::column(statement, next_index)?;
- let x: f64 = x;
- let y: f64 = y;
- let width: f64 = width;
- let height: f64 = height;
- WindowBounds::Fixed(Bounds {
- origin: point(x.into(), y.into()),
- size: size(width.into(), height.into()),
- })
- }
- _ => bail!("Window State did not have a valid string"),
- };
-
- Ok((bounds, next_index + 4))
- }
-}
-
#[derive(Copy, Clone, Debug)]
pub enum WindowAppearance {
Light,
@@ -11,7 +11,7 @@ use objc::{
};
use parking::{Parker, Unparker};
use parking_lot::Mutex;
-use std::{ffi::c_void, sync::Arc, time::Duration};
+use std::{ffi::c_void, ptr::NonNull, sync::Arc, time::Duration};
include!(concat!(env!("OUT_DIR"), "/dispatch_sys.rs"));
@@ -47,7 +47,7 @@ impl PlatformDispatcher for MacDispatcher {
unsafe {
dispatch_async_f(
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT.try_into().unwrap(), 0),
- runnable.into_raw() as *mut c_void,
+ runnable.into_raw().as_ptr() as *mut c_void,
Some(trampoline),
);
}
@@ -57,7 +57,7 @@ impl PlatformDispatcher for MacDispatcher {
unsafe {
dispatch_async_f(
dispatch_get_main_queue(),
- runnable.into_raw() as *mut c_void,
+ runnable.into_raw().as_ptr() as *mut c_void,
Some(trampoline),
);
}
@@ -71,7 +71,7 @@ impl PlatformDispatcher for MacDispatcher {
dispatch_after_f(
when,
queue,
- runnable.into_raw() as *mut c_void,
+ runnable.into_raw().as_ptr() as *mut c_void,
Some(trampoline),
);
}
@@ -91,6 +91,6 @@ impl PlatformDispatcher for MacDispatcher {
}
extern "C" fn trampoline(runnable: *mut c_void) {
- let task = unsafe { Runnable::from_raw(runnable as *mut ()) };
+ let task = unsafe { Runnable::<()>::from_raw(NonNull::new_unchecked(runnable as *mut ())) };
task.run();
}
@@ -16,6 +16,7 @@ float gaussian(float x, float sigma);
float2 erf(float2 x);
float blur_along_x(float x, float y, float sigma, float corner,
float2 half_size);
+float4 over(float4 below, float4 above);
struct QuadVertexOutput {
float4 position [[position]];
@@ -108,21 +109,11 @@ fragment float4 quad_fragment(QuadFragmentInput input [[stage_in]],
color = input.background_color;
} else {
float inset_distance = distance + border_width;
-
- // Decrease border's opacity as we move inside the background.
- input.border_color.a *= 1. - saturate(0.5 - inset_distance);
-
- // Alpha-blend the border and the background.
- float output_alpha = input.border_color.a +
- input.background_color.a * (1. - input.border_color.a);
- float3 premultiplied_border_rgb =
- input.border_color.rgb * input.border_color.a;
- float3 premultiplied_background_rgb =
- input.background_color.rgb * input.background_color.a;
- float3 premultiplied_output_rgb =
- premultiplied_border_rgb +
- premultiplied_background_rgb * (1. - input.border_color.a);
- color = float4(premultiplied_output_rgb, output_alpha);
+ // Blend the border on top of the background and then linearly interpolate
+ // between the two as we slide inside the background.
+ float4 blended_border = over(input.background_color, input.border_color);
+ color = mix(blended_border, input.background_color,
+ saturate(0.5 - inset_distance));
}
return color * float4(1., 1., 1., saturate(0.5 - distance));
@@ -653,3 +644,12 @@ float4 distance_from_clip_rect(float2 unit_vertex, Bounds_ScaledPixels bounds,
position.y - clip_bounds.origin.y,
clip_bounds.origin.y + clip_bounds.size.height - position.y);
}
+
+float4 over(float4 below, float4 above) {
+ float4 result;
+ float alpha = above.a + below.a * (1.0 - above.a);
+ result.rgb =
+ (above.rgb * above.a + below.rgb * below.a * (1.0 - above.a)) / alpha;
+ result.a = alpha;
+ return result;
+}
@@ -19,7 +19,7 @@ pub struct TestPlatform {
background_executor: BackgroundExecutor,
foreground_executor: ForegroundExecutor,
- active_window: Arc<Mutex<Option<AnyWindowHandle>>>,
+ pub(crate) active_window: RefCell<Option<TestWindow>>,
active_display: Rc<dyn PlatformDisplay>,
active_cursor: Mutex<CursorStyle>,
current_clipboard_item: Mutex<Option<ClipboardItem>>,
@@ -79,6 +79,28 @@ impl TestPlatform {
self.prompts.borrow_mut().multiple_choice.push_back(tx);
rx
}
+
+ pub(crate) fn set_active_window(&self, window: Option<TestWindow>) {
+ let executor = self.foreground_executor().clone();
+ let previous_window = self.active_window.borrow_mut().take();
+ *self.active_window.borrow_mut() = window.clone();
+
+ executor
+ .spawn(async move {
+ if let Some(previous_window) = previous_window {
+ if let Some(window) = window.as_ref() {
+ if Arc::ptr_eq(&previous_window.0, &window.0) {
+ return;
+ }
+ }
+ previous_window.simulate_active_status_change(false);
+ }
+ if let Some(window) = window {
+ window.simulate_active_status_change(true);
+ }
+ })
+ .detach();
+ }
}
// todo!("implement out what our tests needed in GPUI 1")
@@ -106,7 +128,7 @@ impl Platform for TestPlatform {
}
fn activate(&self, _ignoring_other_apps: bool) {
- unimplemented!()
+ //
}
fn hide(&self) {
@@ -130,7 +152,10 @@ impl Platform for TestPlatform {
}
fn active_window(&self) -> Option<crate::AnyWindowHandle> {
- self.active_window.lock().clone()
+ self.active_window
+ .borrow()
+ .as_ref()
+ .map(|window| window.0.lock().handle)
}
fn open_window(
@@ -139,12 +164,13 @@ impl Platform for TestPlatform {
options: WindowOptions,
_draw: Box<dyn FnMut() -> Result<Scene>>,
) -> Box<dyn crate::PlatformWindow> {
- *self.active_window.lock() = Some(handle);
- Box::new(TestWindow::new(
+ let window = TestWindow::new(
options,
+ handle,
self.weak.clone(),
self.active_display.clone(),
- ))
+ );
+ Box::new(window)
}
fn set_display_link_output_callback(
@@ -1,7 +1,7 @@
use crate::{
- px, AtlasKey, AtlasTextureId, AtlasTile, Pixels, PlatformAtlas, PlatformDisplay,
- PlatformInputHandler, PlatformWindow, Point, Size, TestPlatform, TileId, WindowAppearance,
- WindowBounds, WindowOptions,
+ px, AnyWindowHandle, AtlasKey, AtlasTextureId, AtlasTile, Bounds, InputEvent, KeyDownEvent,
+ Keystroke, Pixels, PlatformAtlas, PlatformDisplay, PlatformInputHandler, PlatformWindow, Point,
+ Size, TestPlatform, TileId, WindowAppearance, WindowBounds, WindowOptions,
};
use collections::HashMap;
use parking_lot::Mutex;
@@ -10,51 +10,122 @@ use std::{
sync::{self, Arc},
};
-#[derive(Default)]
-pub(crate) struct TestWindowHandlers {
- pub(crate) active_status_change: Vec<Box<dyn FnMut(bool)>>,
- pub(crate) input: Vec<Box<dyn FnMut(crate::InputEvent) -> bool>>,
- pub(crate) moved: Vec<Box<dyn FnMut()>>,
- pub(crate) resize: Vec<Box<dyn FnMut(Size<Pixels>, f32)>>,
-}
-
-pub struct TestWindow {
+pub struct TestWindowState {
pub(crate) bounds: WindowBounds,
+ pub(crate) handle: AnyWindowHandle,
display: Rc<dyn PlatformDisplay>,
pub(crate) title: Option<String>,
pub(crate) edited: bool,
- pub(crate) input_handler: Option<Arc<Mutex<Box<dyn PlatformInputHandler>>>>,
- pub(crate) handlers: Arc<Mutex<TestWindowHandlers>>,
platform: Weak<TestPlatform>,
sprite_atlas: Arc<dyn PlatformAtlas>,
+
+ input_callback: Option<Box<dyn FnMut(InputEvent) -> bool>>,
+ active_status_change_callback: Option<Box<dyn FnMut(bool)>>,
+ resize_callback: Option<Box<dyn FnMut(Size<Pixels>, f32)>>,
+ moved_callback: Option<Box<dyn FnMut()>>,
+ input_handler: Option<Box<dyn PlatformInputHandler>>,
}
+#[derive(Clone)]
+pub struct TestWindow(pub(crate) Arc<Mutex<TestWindowState>>);
+
impl TestWindow {
pub fn new(
options: WindowOptions,
+ handle: AnyWindowHandle,
platform: Weak<TestPlatform>,
display: Rc<dyn PlatformDisplay>,
) -> Self {
- Self {
+ Self(Arc::new(Mutex::new(TestWindowState {
bounds: options.bounds,
display,
platform,
- input_handler: None,
+ handle,
sprite_atlas: Arc::new(TestAtlas::new()),
- handlers: Default::default(),
title: Default::default(),
edited: false,
+
+ input_callback: None,
+ active_status_change_callback: None,
+ resize_callback: None,
+ moved_callback: None,
+ input_handler: None,
+ })))
+ }
+
+ pub fn simulate_resize(&mut self, size: Size<Pixels>) {
+ let scale_factor = self.scale_factor();
+ let mut lock = self.0.lock();
+ let Some(mut callback) = lock.resize_callback.take() else {
+ return;
+ };
+ match &mut lock.bounds {
+ WindowBounds::Fullscreen | WindowBounds::Maximized => {
+ lock.bounds = WindowBounds::Fixed(Bounds {
+ origin: Point::default(),
+ size: size.map(|pixels| f64::from(pixels).into()),
+ });
+ }
+ WindowBounds::Fixed(bounds) => {
+ bounds.size = size.map(|pixels| f64::from(pixels).into());
+ }
}
+ drop(lock);
+ callback(size, scale_factor);
+ self.0.lock().resize_callback = Some(callback);
+ }
+
+ pub(crate) fn simulate_active_status_change(&self, active: bool) {
+ let mut lock = self.0.lock();
+ let Some(mut callback) = lock.active_status_change_callback.take() else {
+ return;
+ };
+ drop(lock);
+ callback(active);
+ self.0.lock().active_status_change_callback = Some(callback);
+ }
+
+ pub fn simulate_input(&mut self, event: InputEvent) -> bool {
+ let mut lock = self.0.lock();
+ let Some(mut callback) = lock.input_callback.take() else {
+ return false;
+ };
+ drop(lock);
+ let result = callback(event);
+ self.0.lock().input_callback = Some(callback);
+ result
+ }
+
+ pub fn simulate_keystroke(&mut self, keystroke: Keystroke, is_held: bool) {
+ if self.simulate_input(InputEvent::KeyDown(KeyDownEvent {
+ keystroke: keystroke.clone(),
+ is_held,
+ })) {
+ return;
+ }
+
+ let mut lock = self.0.lock();
+ let Some(mut input_handler) = lock.input_handler.take() else {
+ panic!(
+ "simulate_keystroke {:?} input event was not handled and there was no active input",
+ &keystroke
+ );
+ };
+ drop(lock);
+ let text = keystroke.ime_key.unwrap_or(keystroke.key);
+ input_handler.replace_text_in_range(None, &text);
+
+ self.0.lock().input_handler = Some(input_handler);
}
}
impl PlatformWindow for TestWindow {
fn bounds(&self) -> WindowBounds {
- self.bounds
+ self.0.lock().bounds
}
fn content_size(&self) -> Size<Pixels> {
- let bounds = match self.bounds {
+ let bounds = match self.bounds() {
WindowBounds::Fixed(bounds) => bounds,
WindowBounds::Maximized | WindowBounds::Fullscreen => self.display().bounds(),
};
@@ -74,7 +145,7 @@ impl PlatformWindow for TestWindow {
}
fn display(&self) -> std::rc::Rc<dyn crate::PlatformDisplay> {
- self.display.clone()
+ self.0.lock().display.clone()
}
fn mouse_position(&self) -> Point<Pixels> {
@@ -90,11 +161,11 @@ impl PlatformWindow for TestWindow {
}
fn set_input_handler(&mut self, input_handler: Box<dyn crate::PlatformInputHandler>) {
- self.input_handler = Some(Arc::new(Mutex::new(input_handler)));
+ self.0.lock().input_handler = Some(input_handler);
}
fn clear_input_handler(&mut self) {
- self.input_handler = None;
+ self.0.lock().input_handler = None;
}
fn prompt(
@@ -103,19 +174,29 @@ impl PlatformWindow for TestWindow {
_msg: &str,
_answers: &[&str],
) -> futures::channel::oneshot::Receiver<usize> {
- self.platform.upgrade().expect("platform dropped").prompt()
+ self.0
+ .lock()
+ .platform
+ .upgrade()
+ .expect("platform dropped")
+ .prompt()
}
fn activate(&self) {
- unimplemented!()
+ self.0
+ .lock()
+ .platform
+ .upgrade()
+ .unwrap()
+ .set_active_window(Some(self.clone()))
}
fn set_title(&mut self, title: &str) {
- self.title = Some(title.to_owned());
+ self.0.lock().title = Some(title.to_owned());
}
fn set_edited(&mut self, edited: bool) {
- self.edited = edited;
+ self.0.lock().edited = edited;
}
fn show_character_palette(&self) {
@@ -135,15 +216,15 @@ impl PlatformWindow for TestWindow {
}
fn on_input(&self, callback: Box<dyn FnMut(crate::InputEvent) -> bool>) {
- self.handlers.lock().input.push(callback)
+ self.0.lock().input_callback = Some(callback)
}
fn on_active_status_change(&self, callback: Box<dyn FnMut(bool)>) {
- self.handlers.lock().active_status_change.push(callback)
+ self.0.lock().active_status_change_callback = Some(callback)
}
fn on_resize(&self, callback: Box<dyn FnMut(Size<Pixels>, f32)>) {
- self.handlers.lock().resize.push(callback)
+ self.0.lock().resize_callback = Some(callback)
}
fn on_fullscreen(&self, _callback: Box<dyn FnMut(bool)>) {
@@ -151,7 +232,7 @@ impl PlatformWindow for TestWindow {
}
fn on_moved(&self, callback: Box<dyn FnMut()>) {
- self.handlers.lock().moved.push(callback)
+ self.0.lock().moved_callback = Some(callback)
}
fn on_should_close(&self, _callback: Box<dyn FnMut() -> bool>) {
@@ -175,7 +256,7 @@ impl PlatformWindow for TestWindow {
}
fn sprite_atlas(&self) -> sync::Arc<dyn crate::PlatformAtlas> {
- self.sprite_atlas.clone()
+ self.0.lock().sprite_atlas.clone()
}
fn as_test(&mut self) -> Option<&mut TestWindow> {
@@ -15,8 +15,9 @@ use crate::{
use anyhow::anyhow;
use collections::FxHashMap;
use core::fmt;
+use itertools::Itertools;
use parking_lot::{Mutex, RwLock, RwLockUpgradableReadGuard};
-use smallvec::SmallVec;
+use smallvec::{smallvec, SmallVec};
use std::{
cmp,
fmt::{Debug, Display, Formatter},
@@ -42,6 +43,7 @@ pub struct TextSystem {
raster_bounds: RwLock<FxHashMap<RenderGlyphParams, Bounds<DevicePixels>>>,
wrapper_pool: Mutex<FxHashMap<FontIdWithSize, Vec<LineWrapper>>>,
font_runs_pool: Mutex<Vec<Vec<FontRun>>>,
+ fallback_font_stack: SmallVec<[Font; 2]>,
}
impl TextSystem {
@@ -54,6 +56,12 @@ impl TextSystem {
font_ids_by_font: RwLock::default(),
wrapper_pool: Mutex::default(),
font_runs_pool: Mutex::default(),
+ fallback_font_stack: smallvec![
+ // TODO: This is currently Zed-specific.
+ // We should allow GPUI users to provide their own fallback font stack.
+ font("Zed Mono"),
+ font("Helvetica")
+ ],
}
}
@@ -72,6 +80,33 @@ impl TextSystem {
}
}
+ /// Resolves the specified font, falling back to the default font stack if
+ /// the font fails to load.
+ ///
+ /// # Panics
+ ///
+ /// Panics if the font and none of the fallbacks can be resolved.
+ pub fn resolve_font(&self, font: &Font) -> FontId {
+ if let Ok(font_id) = self.font_id(font) {
+ return font_id;
+ }
+
+ for fallback in &self.fallback_font_stack {
+ if let Ok(font_id) = self.font_id(fallback) {
+ return font_id;
+ }
+ }
+
+ panic!(
+ "failed to resolve font '{}' or any of the fallbacks: {}",
+ font.family,
+ self.fallback_font_stack
+ .iter()
+ .map(|fallback| &fallback.family)
+ .join(", ")
+ );
+ }
+
pub fn bounding_box(&self, font_id: FontId, font_size: Pixels) -> Bounds<Pixels> {
self.read_metrics(font_id, |metrics| metrics.bounding_box(font_size))
}
@@ -159,7 +194,7 @@ impl TextSystem {
) -> Result<Arc<LineLayout>> {
let mut font_runs = self.font_runs_pool.lock().pop().unwrap_or_default();
for run in runs.iter() {
- let font_id = self.font_id(&run.font)?;
+ let font_id = self.resolve_font(&run.font);
if let Some(last_run) = font_runs.last_mut() {
if last_run.font_id == font_id {
last_run.len += run.len;
@@ -253,7 +288,7 @@ impl TextSystem {
last_font = Some(run.font.clone());
font_runs.push(FontRun {
len: run_len_within_line,
- font_id: self.platform_text_system.font_id(&run.font)?,
+ font_id: self.resolve_font(&run.font),
});
}
@@ -143,6 +143,11 @@ impl<V: 'static> WeakView<V> {
let view = self.upgrade().context("error upgrading view")?;
Ok(view.update(cx, f)).flatten()
}
+
+ #[cfg(any(test, feature = "test-support"))]
+ pub fn assert_dropped(&self) {
+ self.model.assert_dropped()
+ }
}
impl<V> Clone for WeakView<V> {
@@ -1583,36 +1583,16 @@ impl<'a> WindowContext<'a> {
let mut actions: Vec<Box<dyn Action>> = Vec::new();
- // Capture phase
let mut context_stack: SmallVec<[KeyContext; 16]> = SmallVec::new();
- self.propagate_event = true;
-
for node_id in &dispatch_path {
let node = self.window.rendered_frame.dispatch_tree.node(*node_id);
if let Some(context) = node.context.clone() {
context_stack.push(context);
}
-
- for key_listener in node.key_listeners.clone() {
- key_listener(event, DispatchPhase::Capture, self);
- if !self.propagate_event {
- return;
- }
- }
}
- // Bubble phase
for node_id in dispatch_path.iter().rev() {
- // Handle low level key events
- let node = self.window.rendered_frame.dispatch_tree.node(*node_id);
- for key_listener in node.key_listeners.clone() {
- key_listener(event, DispatchPhase::Bubble, self);
- if !self.propagate_event {
- return;
- }
- }
-
// Match keystrokes
let node = self.window.rendered_frame.dispatch_tree.node(*node_id);
if node.context.is_some() {
@@ -1633,6 +1613,7 @@ impl<'a> WindowContext<'a> {
self.clear_pending_keystrokes();
}
+ self.propagate_event = true;
for action in actions {
self.dispatch_action_on_node(node_id, action.boxed_clone());
if !self.propagate_event {
@@ -1640,6 +1621,31 @@ impl<'a> WindowContext<'a> {
return;
}
}
+
+ // Capture phase
+ for node_id in &dispatch_path {
+ let node = self.window.rendered_frame.dispatch_tree.node(*node_id);
+
+ for key_listener in node.key_listeners.clone() {
+ key_listener(event, DispatchPhase::Capture, self);
+ if !self.propagate_event {
+ return;
+ }
+ }
+ }
+
+ // Bubble phase
+ for node_id in dispatch_path.iter().rev() {
+ // Handle low level key events
+ let node = self.window.rendered_frame.dispatch_tree.node(*node_id);
+ for key_listener in node.key_listeners.clone() {
+ key_listener(event, DispatchPhase::Bubble, self);
+ if !self.propagate_event {
+ return;
+ }
+ }
+ }
+
self.dispatch_keystroke_observers(event, None);
}
@@ -57,6 +57,12 @@ lazy_static! {
pub static ref BUFFER_DIFF_TASK: TaskLabel = TaskLabel::new();
}
+#[derive(PartialEq, Clone, Copy, Debug)]
+pub enum Capability {
+ ReadWrite,
+ ReadOnly,
+}
+
pub struct Buffer {
text: TextBuffer,
diff_base: Option<String>,
@@ -90,6 +96,7 @@ pub struct Buffer {
completion_triggers: Vec<String>,
completion_triggers_timestamp: clock::Lamport,
deferred_ops: OperationQueue<Operation>,
+ capability: Capability,
}
pub struct BufferSnapshot {
@@ -405,19 +412,27 @@ impl Buffer {
TextBuffer::new(replica_id, id, base_text.into()),
None,
None,
+ Capability::ReadWrite,
)
}
- pub fn remote(remote_id: u64, replica_id: ReplicaId, base_text: String) -> Self {
+ pub fn remote(
+ remote_id: u64,
+ replica_id: ReplicaId,
+ capability: Capability,
+ base_text: String,
+ ) -> Self {
Self::build(
TextBuffer::new(replica_id, remote_id, base_text),
None,
None,
+ capability,
)
}
pub fn from_proto(
replica_id: ReplicaId,
+ capability: Capability,
message: proto::BufferState,
file: Option<Arc<dyn File>>,
) -> Result<Self> {
@@ -426,6 +441,7 @@ impl Buffer {
buffer,
message.diff_base.map(|text| text.into_boxed_str().into()),
file,
+ capability,
);
this.text.set_line_ending(proto::deserialize_line_ending(
rpc::proto::LineEnding::from_i32(message.line_ending)
@@ -504,10 +520,19 @@ impl Buffer {
self
}
+ pub fn capability(&self) -> Capability {
+ self.capability
+ }
+
+ pub fn read_only(&self) -> bool {
+ self.capability == Capability::ReadOnly
+ }
+
pub fn build(
buffer: TextBuffer,
diff_base: Option<String>,
file: Option<Arc<dyn File>>,
+ capability: Capability,
) -> Self {
let saved_mtime = if let Some(file) = file.as_ref() {
file.mtime()
@@ -526,6 +551,7 @@ impl Buffer {
diff_base,
git_diff: git::diff::BufferDiff::new(),
file,
+ capability,
syntax_map: Mutex::new(SyntaxMap::new()),
parsing_in_background: false,
parse_count: 0,
@@ -1926,7 +1926,7 @@ fn test_serialization(cx: &mut gpui::AppContext) {
.background_executor()
.block(buffer1.read(cx).serialize_ops(None, cx));
let buffer2 = cx.new_model(|cx| {
- let mut buffer = Buffer::from_proto(1, state, None).unwrap();
+ let mut buffer = Buffer::from_proto(1, Capability::ReadWrite, state, None).unwrap();
buffer
.apply_ops(
ops.into_iter()
@@ -1967,7 +1967,8 @@ fn test_random_collaboration(cx: &mut AppContext, mut rng: StdRng) {
let ops = cx
.background_executor()
.block(base_buffer.read(cx).serialize_ops(None, cx));
- let mut buffer = Buffer::from_proto(i as ReplicaId, state, None).unwrap();
+ let mut buffer =
+ Buffer::from_proto(i as ReplicaId, Capability::ReadWrite, state, None).unwrap();
buffer
.apply_ops(
ops.into_iter()
@@ -2083,8 +2084,13 @@ fn test_random_collaboration(cx: &mut AppContext, mut rng: StdRng) {
replica_id
);
new_buffer = Some(cx.new_model(|cx| {
- let mut new_buffer =
- Buffer::from_proto(new_replica_id, old_buffer_state, None).unwrap();
+ let mut new_buffer = Buffer::from_proto(
+ new_replica_id,
+ Capability::ReadWrite,
+ old_buffer_state,
+ None,
+ )
+ .unwrap();
new_buffer
.apply_ops(
old_buffer_ops
@@ -113,7 +113,6 @@ pub struct LanguageServerName(pub Arc<str>);
pub struct CachedLspAdapter {
pub name: LanguageServerName,
pub short_name: &'static str,
- pub initialization_options: Option<Value>,
pub disk_based_diagnostic_sources: Vec<String>,
pub disk_based_diagnostics_progress_token: Option<String>,
pub language_ids: HashMap<String, String>,
@@ -125,7 +124,6 @@ impl CachedLspAdapter {
pub async fn new(adapter: Arc<dyn LspAdapter>) -> Arc<Self> {
let name = adapter.name().await;
let short_name = adapter.short_name();
- let initialization_options = adapter.initialization_options().await;
let disk_based_diagnostic_sources = adapter.disk_based_diagnostic_sources().await;
let disk_based_diagnostics_progress_token =
adapter.disk_based_diagnostics_progress_token().await;
@@ -134,7 +132,6 @@ impl CachedLspAdapter {
Arc::new(CachedLspAdapter {
name,
short_name,
- initialization_options,
disk_based_diagnostic_sources,
disk_based_diagnostics_progress_token,
language_ids,
@@ -10,7 +10,7 @@ use language::{LanguageServerId, LanguageServerName};
use lsp::IoKind;
use project::{search::SearchQuery, Project};
use std::{borrow::Cow, sync::Arc};
-use ui::{h_stack, popover_menu, Button, Checkbox, Clickable, ContextMenu, Label, Selection};
+use ui::{popover_menu, prelude::*, Button, Checkbox, ContextMenu, Label, Selection};
use workspace::{
item::{Item, ItemHandle},
searchable::{SearchEvent, SearchableItem, SearchableItemHandle},
@@ -614,8 +614,14 @@ impl Item for LspLogView {
Editor::to_item_events(event, f)
}
- fn tab_content(&self, _: Option<usize>, _: bool, _: &WindowContext<'_>) -> AnyElement {
- Label::new("LSP Logs").into_any_element()
+ fn tab_content(&self, _: Option<usize>, selected: bool, _: &WindowContext<'_>) -> AnyElement {
+ Label::new("LSP Logs")
+ .color(if selected {
+ Color::Default
+ } else {
+ Color::Muted
+ })
+ .into_any_element()
}
fn as_searchable(&self, handle: &View<Self>) -> Option<Box<dyn SearchableItemHandle>> {
@@ -766,9 +772,10 @@ impl Render for LspLogToolbarItemView {
}),
);
if server_selected && row.logs_selected {
+ let selected_ix = menu.select_last();
debug_assert_eq!(
Some(ix * 3 + 1),
- menu.select_last(),
+ selected_ix,
"Could not scroll to a just added LSP menu item"
);
}
@@ -816,9 +823,10 @@ impl Render for LspLogToolbarItemView {
}),
);
if server_selected && row.rpc_trace_selected {
+ let selected_ix = menu.select_last();
debug_assert_eq!(
Some(ix * 3 + 2),
- menu.select_last(),
+ selected_ix,
"Could not scroll to a just added LSP menu item"
);
}
@@ -405,8 +405,14 @@ impl Item for SyntaxTreeView {
fn to_item_events(_: &Self::Event, _: impl FnMut(workspace::item::ItemEvent)) {}
- fn tab_content(&self, _: Option<usize>, _: bool, _: &WindowContext<'_>) -> AnyElement {
- Label::new("Syntax Tree").into_any_element()
+ fn tab_content(&self, _: Option<usize>, selected: bool, _: &WindowContext<'_>) -> AnyElement {
+ Label::new("Syntax Tree")
+ .color(if selected {
+ Color::Default
+ } else {
+ Color::Muted
+ })
+ .into_any_element()
}
fn clone_on_split(
@@ -62,6 +62,7 @@ impl<'a> VideoGrant<'a> {
Self {
room: Some(Cow::Borrowed(room)),
room_join: Some(true),
+ can_publish: Some(false),
can_subscribe: Some(true),
..Default::default()
}
@@ -11,7 +11,7 @@ pub use language::Completion;
use language::{
char_kind,
language_settings::{language_settings, LanguageSettings},
- AutoindentMode, Buffer, BufferChunks, BufferSnapshot, CharKind, Chunk, CursorShape,
+ AutoindentMode, Buffer, BufferChunks, BufferSnapshot, Capability, 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,
@@ -55,6 +55,7 @@ pub struct MultiBuffer {
replica_id: ReplicaId,
history: History,
title: Option<String>,
+ capability: Capability,
}
#[derive(Clone, Debug, PartialEq, Eq)]
@@ -225,13 +226,14 @@ struct ExcerptBytes<'a> {
}
impl MultiBuffer {
- pub fn new(replica_id: ReplicaId) -> Self {
+ pub fn new(replica_id: ReplicaId, capability: Capability) -> Self {
Self {
snapshot: Default::default(),
buffers: Default::default(),
next_excerpt_id: 1,
subscriptions: Default::default(),
singleton: false,
+ capability,
replica_id,
history: History {
next_transaction_id: Default::default(),
@@ -271,6 +273,7 @@ impl MultiBuffer {
next_excerpt_id: 1,
subscriptions: Default::default(),
singleton: self.singleton,
+ capability: self.capability,
replica_id: self.replica_id,
history: self.history.clone(),
title: self.title.clone(),
@@ -282,8 +285,12 @@ impl MultiBuffer {
self
}
+ pub fn read_only(&self) -> bool {
+ self.capability == Capability::ReadOnly
+ }
+
pub fn singleton(buffer: Model<Buffer>, cx: &mut ModelContext<Self>) -> Self {
- let mut this = Self::new(buffer.read(cx).replica_id());
+ let mut this = Self::new(buffer.read(cx).replica_id(), buffer.read(cx).capability());
this.singleton = true;
this.push_excerpts(
buffer,
@@ -1657,7 +1664,7 @@ impl MultiBuffer {
excerpts: [(&str, Vec<Range<Point>>); COUNT],
cx: &mut gpui::AppContext,
) -> Model<Self> {
- let multi = cx.new_model(|_| Self::new(0));
+ let multi = cx.new_model(|_| Self::new(0, Capability::ReadWrite));
for (text, ranges) in excerpts {
let buffer = cx.new_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), text));
let excerpt_ranges = ranges.into_iter().map(|range| ExcerptRange {
@@ -1678,7 +1685,7 @@ impl MultiBuffer {
pub fn build_random(rng: &mut impl rand::Rng, cx: &mut gpui::AppContext) -> Model<Self> {
cx.new_model(|cx| {
- let mut multibuffer = MultiBuffer::new(0);
+ let mut multibuffer = MultiBuffer::new(0, Capability::ReadWrite);
let mutation_count = rng.gen_range(1..=5);
multibuffer.randomly_edit_excerpts(rng, mutation_count, cx);
multibuffer
@@ -4176,7 +4183,7 @@ mod tests {
let ops = cx
.background_executor()
.block(host_buffer.read(cx).serialize_ops(None, cx));
- let mut buffer = Buffer::from_proto(1, state, None).unwrap();
+ let mut buffer = Buffer::from_proto(1, Capability::ReadWrite, state, None).unwrap();
buffer
.apply_ops(
ops.into_iter()
@@ -4205,7 +4212,7 @@ mod tests {
cx.new_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), sample_text(6, 6, 'a')));
let buffer_2 =
cx.new_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), sample_text(6, 6, 'g')));
- let multibuffer = cx.new_model(|_| MultiBuffer::new(0));
+ let multibuffer = cx.new_model(|_| MultiBuffer::new(0, Capability::ReadWrite));
let events = Arc::new(RwLock::new(Vec::<Event>::new()));
multibuffer.update(cx, |_, cx| {
@@ -4442,8 +4449,8 @@ mod tests {
let buffer_2 =
cx.new_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), sample_text(10, 3, 'm')));
- let leader_multibuffer = cx.new_model(|_| MultiBuffer::new(0));
- let follower_multibuffer = cx.new_model(|_| MultiBuffer::new(0));
+ let leader_multibuffer = cx.new_model(|_| MultiBuffer::new(0, Capability::ReadWrite));
+ let follower_multibuffer = cx.new_model(|_| MultiBuffer::new(0, Capability::ReadWrite));
let follower_edit_event_count = Arc::new(RwLock::new(0));
follower_multibuffer.update(cx, |_, cx| {
@@ -4547,7 +4554,7 @@ mod tests {
fn test_push_excerpts_with_context_lines(cx: &mut AppContext) {
let buffer =
cx.new_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), sample_text(20, 3, 'a')));
- let multibuffer = cx.new_model(|_| MultiBuffer::new(0));
+ let multibuffer = cx.new_model(|_| MultiBuffer::new(0, Capability::ReadWrite));
let anchor_ranges = multibuffer.update(cx, |multibuffer, cx| {
multibuffer.push_excerpts_with_context_lines(
buffer.clone(),
@@ -4584,7 +4591,7 @@ mod tests {
async fn test_stream_excerpts_with_context_lines(cx: &mut TestAppContext) {
let buffer =
cx.new_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), sample_text(20, 3, 'a')));
- let multibuffer = cx.new_model(|_| MultiBuffer::new(0));
+ let multibuffer = cx.new_model(|_| MultiBuffer::new(0, Capability::ReadWrite));
let anchor_ranges = multibuffer.update(cx, |multibuffer, cx| {
let snapshot = buffer.read(cx);
let ranges = vec![
@@ -4619,7 +4626,7 @@ mod tests {
#[gpui::test]
fn test_empty_multibuffer(cx: &mut AppContext) {
- let multibuffer = cx.new_model(|_| MultiBuffer::new(0));
+ let multibuffer = cx.new_model(|_| MultiBuffer::new(0, Capability::ReadWrite));
let snapshot = multibuffer.read(cx).snapshot(cx);
assert_eq!(snapshot.text(), "");
@@ -4652,7 +4659,7 @@ mod tests {
let buffer_1 = cx.new_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), "abcd"));
let buffer_2 = cx.new_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), "efghi"));
let multibuffer = cx.new_model(|cx| {
- let mut multibuffer = MultiBuffer::new(0);
+ let mut multibuffer = MultiBuffer::new(0, Capability::ReadWrite);
multibuffer.push_excerpts(
buffer_1.clone(),
[ExcerptRange {
@@ -4710,7 +4717,7 @@ mod tests {
let buffer_1 = cx.new_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), "abcd"));
let buffer_2 =
cx.new_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), "ABCDEFGHIJKLMNOP"));
- let multibuffer = cx.new_model(|_| MultiBuffer::new(0));
+ let multibuffer = cx.new_model(|_| MultiBuffer::new(0, Capability::ReadWrite));
// 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.
@@ -4844,7 +4851,7 @@ mod tests {
.unwrap_or(10);
let mut buffers: Vec<Model<Buffer>> = Vec::new();
- let multibuffer = cx.new_model(|_| MultiBuffer::new(0));
+ let multibuffer = cx.new_model(|_| MultiBuffer::new(0, Capability::ReadWrite));
let mut excerpt_ids = Vec::<ExcerptId>::new();
let mut expected_excerpts = Vec::<(Model<Buffer>, Range<text::Anchor>)>::new();
let mut anchors = Vec::new();
@@ -5266,7 +5273,7 @@ mod tests {
let buffer_1 = cx.new_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), "1234"));
let buffer_2 = cx.new_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), "5678"));
- let multibuffer = cx.new_model(|_| MultiBuffer::new(0));
+ let multibuffer = cx.new_model(|_| MultiBuffer::new(0, Capability::ReadWrite));
let group_interval = multibuffer.read(cx).history.group_interval;
multibuffer.update(cx, |multibuffer, cx| {
multibuffer.push_excerpts(
@@ -39,11 +39,11 @@ use language::{
deserialize_anchor, deserialize_fingerprint, deserialize_line_ending, deserialize_version,
serialize_anchor, serialize_version, split_operations,
},
- range_from_lsp, range_to_lsp, Bias, Buffer, BufferSnapshot, CachedLspAdapter, CodeAction,
- CodeLabel, Completion, Diagnostic, DiagnosticEntry, DiagnosticSet, Diff, Event as BufferEvent,
- File as _, Language, LanguageRegistry, LanguageServerName, LocalFile, LspAdapterDelegate,
- OffsetRangeExt, Operation, Patch, PendingLanguageServer, PointUtf16, TextBufferSnapshot,
- ToOffset, ToPointUtf16, Transaction, Unclipped,
+ range_from_lsp, range_to_lsp, Bias, Buffer, BufferSnapshot, CachedLspAdapter, Capability,
+ CodeAction, CodeLabel, Completion, Diagnostic, DiagnosticEntry, DiagnosticSet, Diff,
+ Event as BufferEvent, File as _, Language, LanguageRegistry, LanguageServerName, LocalFile,
+ LspAdapterDelegate, OffsetRangeExt, Operation, Patch, PendingLanguageServer, PointUtf16,
+ TextBufferSnapshot, ToOffset, ToPointUtf16, Transaction, Unclipped,
};
use log::error;
use lsp::{
@@ -262,6 +262,7 @@ enum ProjectClientState {
},
Remote {
sharing_has_stopped: bool,
+ capability: Capability,
remote_id: u64,
replica_id: ReplicaId,
},
@@ -702,6 +703,7 @@ impl Project {
user_store: Model<UserStore>,
languages: Arc<LanguageRegistry>,
fs: Arc<dyn Fs>,
+ role: proto::ChannelRole,
mut cx: AsyncAppContext,
) -> Result<Model<Self>> {
client.authenticate_and_connect(true, &cx).await?;
@@ -756,6 +758,7 @@ impl Project {
client: client.clone(),
client_state: Some(ProjectClientState::Remote {
sharing_has_stopped: false,
+ capability: Capability::ReadWrite,
remote_id,
replica_id,
}),
@@ -796,6 +799,7 @@ impl Project {
prettiers_per_worktree: HashMap::default(),
prettier_instances: HashMap::default(),
};
+ this.set_role(role);
for worktree in worktrees {
let _ = this.add_worktree(&worktree, cx);
}
@@ -1618,6 +1622,17 @@ impl Project {
cx.notify();
}
+ pub fn set_role(&mut self, role: proto::ChannelRole) {
+ if let Some(ProjectClientState::Remote { capability, .. }) = &mut self.client_state {
+ *capability = if role == proto::ChannelRole::Member || role == proto::ChannelRole::Admin
+ {
+ Capability::ReadWrite
+ } else {
+ Capability::ReadOnly
+ };
+ }
+ }
+
fn disconnected_from_host_internal(&mut self, cx: &mut AppContext) {
if let Some(ProjectClientState::Remote {
sharing_has_stopped,
@@ -1659,7 +1674,7 @@ impl Project {
cx.emit(Event::Closed);
}
- pub fn is_read_only(&self) -> bool {
+ pub fn is_disconnected(&self) -> bool {
match &self.client_state {
Some(ProjectClientState::Remote {
sharing_has_stopped,
@@ -1669,6 +1684,17 @@ impl Project {
}
}
+ pub fn capability(&self) -> Capability {
+ match &self.client_state {
+ Some(ProjectClientState::Remote { capability, .. }) => *capability,
+ Some(ProjectClientState::Local { .. }) | None => Capability::ReadWrite,
+ }
+ }
+
+ pub fn is_read_only(&self) -> bool {
+ self.is_disconnected() || self.capability() == Capability::ReadOnly
+ }
+
pub fn is_local(&self) -> bool {
match &self.client_state {
Some(ProjectClientState::Remote { .. }) => false,
@@ -2816,15 +2842,6 @@ impl Project {
let lsp = project_settings.lsp.get(&adapter.name.0);
let override_options = lsp.map(|s| s.initialization_options.clone()).flatten();
- let mut initialization_options = adapter.initialization_options.clone();
- match (&mut initialization_options, override_options) {
- (Some(initialization_options), Some(override_options)) => {
- merge_json_value_into(override_options, initialization_options);
- }
- (None, override_options) => initialization_options = override_options,
- _ => {}
- }
-
let server_id = pending_server.server_id;
let container_dir = pending_server.container_dir.clone();
let state = LanguageServerState::Starting({
@@ -2837,7 +2854,7 @@ impl Project {
let result = Self::setup_and_insert_language_server(
this.clone(),
&worktree_path,
- initialization_options,
+ override_options,
pending_server,
adapter.clone(),
language.clone(),
@@ -2958,7 +2975,7 @@ impl Project {
async fn setup_and_insert_language_server(
this: WeakModel<Self>,
worktree_path: &Path,
- initialization_options: Option<serde_json::Value>,
+ override_initialization_options: Option<serde_json::Value>,
pending_server: PendingLanguageServer,
adapter: Arc<CachedLspAdapter>,
language: Arc<Language>,
@@ -2968,7 +2985,7 @@ impl Project {
) -> Result<Option<Arc<LanguageServer>>> {
let language_server = Self::setup_pending_language_server(
this.clone(),
- initialization_options,
+ override_initialization_options,
pending_server,
worktree_path,
adapter.clone(),
@@ -2998,7 +3015,7 @@ impl Project {
async fn setup_pending_language_server(
this: WeakModel<Self>,
- initialization_options: Option<serde_json::Value>,
+ override_options: Option<serde_json::Value>,
pending_server: PendingLanguageServer,
worktree_path: &Path,
adapter: Arc<CachedLspAdapter>,
@@ -3164,7 +3181,14 @@ impl Project {
}
})
.detach();
-
+ let mut initialization_options = adapter.adapter.initialization_options().await;
+ match (&mut initialization_options, override_options) {
+ (Some(initialization_options), Some(override_options)) => {
+ merge_json_value_into(override_options, initialization_options);
+ }
+ (None, override_options) => initialization_options = override_options,
+ _ => {}
+ }
let language_server = language_server.initialize(initialization_options).await?;
language_server
@@ -6015,7 +6039,7 @@ impl Project {
this.upgrade().context("project dropped")?;
let response = rpc.request(message).await?;
let this = this.upgrade().context("project dropped")?;
- if this.update(&mut cx, |this, _| this.is_read_only())? {
+ if this.update(&mut cx, |this, _| this.is_disconnected())? {
Err(anyhow!("disconnected before completing request"))
} else {
request
@@ -7194,7 +7218,8 @@ impl Project {
let buffer_id = state.id;
let buffer = cx.new_model(|_| {
- Buffer::from_proto(this.replica_id(), state, buffer_file).unwrap()
+ Buffer::from_proto(this.replica_id(), this.capability(), state, buffer_file)
+ .unwrap()
});
this.incomplete_remote_buffers
.insert(buffer_id, Some(buffer));
@@ -7942,7 +7967,7 @@ impl Project {
if let Some(buffer) = buffer {
break buffer;
- } else if this.update(&mut cx, |this, _| this.is_read_only())? {
+ } else if this.update(&mut cx, |this, _| this.is_disconnected())? {
return Err(anyhow!("disconnected before buffer {} could be opened", id));
}
@@ -32,7 +32,8 @@ use language::{
deserialize_fingerprint, deserialize_version, serialize_fingerprint, serialize_line_ending,
serialize_version,
},
- Buffer, DiagnosticEntry, File as _, LineEnding, PointUtf16, Rope, RopeFingerprint, Unclipped,
+ Buffer, Capability, DiagnosticEntry, File as _, LineEnding, PointUtf16, Rope, RopeFingerprint,
+ Unclipped,
};
use lsp::LanguageServerId;
use parking_lot::Mutex;
@@ -682,7 +683,14 @@ impl LocalWorktree {
.background_executor()
.spawn(async move { text::Buffer::new(0, id, contents) })
.await;
- cx.new_model(|_| Buffer::build(text_buffer, diff_base, Some(Arc::new(file))))
+ cx.new_model(|_| {
+ Buffer::build(
+ text_buffer,
+ diff_base,
+ Some(Arc::new(file)),
+ Capability::ReadWrite,
+ )
+ })
})
}
@@ -388,8 +388,18 @@ impl ProjectPanel {
let is_dir = entry.is_dir();
let worktree_id = worktree.id();
let is_local = project.is_local();
+ let is_read_only = project.is_read_only();
let context_menu = ContextMenu::build(cx, |mut menu, cx| {
+ if is_read_only {
+ menu = menu.action("Copy Relative Path", Box::new(CopyRelativePath));
+ if is_dir {
+ menu = menu.action("Search Inside", Box::new(NewSearchInDirectory))
+ }
+
+ return menu;
+ }
+
if is_local {
menu = menu.action(
"Add Folder to Project",
@@ -971,25 +981,16 @@ impl ProjectPanel {
}
}
- fn open_in_terminal(&mut self, _: &OpenInTerminal, _cx: &mut ViewContext<Self>) {
- todo!()
- // if let Some((worktree, entry)) = self.selected_entry(cx) {
- // let window = cx.window();
- // let view_id = cx.view_id();
- // let path = worktree.abs_path().join(&entry.path);
-
- // cx.app_context()
- // .spawn(|mut cx| async move {
- // window.dispatch_action(
- // view_id,
- // &workspace::OpenTerminal {
- // working_directory: path,
- // },
- // &mut cx,
- // );
- // })
- // .detach();
- // }
+ fn open_in_terminal(&mut self, _: &OpenInTerminal, cx: &mut ViewContext<Self>) {
+ if let Some((worktree, entry)) = self.selected_entry(cx) {
+ let path = worktree.abs_path().join(&entry.path);
+ cx.dispatch_action(
+ workspace::OpenTerminal {
+ working_directory: path,
+ }
+ .boxed_clone(),
+ )
+ }
}
pub fn new_search_in_directory(
@@ -1404,7 +1405,7 @@ impl ProjectPanel {
.child(if let Some(icon) = &icon {
div().child(IconElement::from_path(icon.to_string()).color(Color::Muted))
} else {
- div()
+ div().size(IconSize::default().rems()).invisible()
})
.child(
if let (Some(editor), true) = (Some(&self.filename_editor), show_editor) {
@@ -1482,6 +1483,7 @@ impl ProjectPanel {
impl Render for ProjectPanel {
fn render(&mut self, cx: &mut gpui::ViewContext<Self>) -> impl IntoElement {
let has_worktree = self.visible_entries.len() != 0;
+ let project = self.project.read(cx);
if has_worktree {
div()
@@ -1494,21 +1496,25 @@ impl Render for ProjectPanel {
.on_action(cx.listener(Self::expand_selected_entry))
.on_action(cx.listener(Self::collapse_selected_entry))
.on_action(cx.listener(Self::collapse_all_entries))
- .on_action(cx.listener(Self::new_file))
- .on_action(cx.listener(Self::new_directory))
- .on_action(cx.listener(Self::rename))
- .on_action(cx.listener(Self::delete))
- .on_action(cx.listener(Self::confirm))
.on_action(cx.listener(Self::open_file))
+ .on_action(cx.listener(Self::confirm))
.on_action(cx.listener(Self::cancel))
- .on_action(cx.listener(Self::cut))
- .on_action(cx.listener(Self::copy))
.on_action(cx.listener(Self::copy_path))
.on_action(cx.listener(Self::copy_relative_path))
- .on_action(cx.listener(Self::paste))
- .on_action(cx.listener(Self::reveal_in_finder))
- .on_action(cx.listener(Self::open_in_terminal))
.on_action(cx.listener(Self::new_search_in_directory))
+ .when(!project.is_read_only(), |el| {
+ el.on_action(cx.listener(Self::new_file))
+ .on_action(cx.listener(Self::new_directory))
+ .on_action(cx.listener(Self::rename))
+ .on_action(cx.listener(Self::delete))
+ .on_action(cx.listener(Self::cut))
+ .on_action(cx.listener(Self::copy))
+ .on_action(cx.listener(Self::paste))
+ })
+ .when(project.is_local(), |el| {
+ el.on_action(cx.listener(Self::reveal_in_finder))
+ .on_action(cx.listener(Self::open_in_terminal))
+ })
.track_focus(&self.focus_handle)
.child(
uniform_list(
@@ -395,6 +395,7 @@ mod tests {
language::init(cx);
Project::init_settings(cx);
workspace::init_settings(cx);
+ editor::init(cx);
});
}
@@ -269,6 +269,7 @@ message Participant {
repeated ParticipantProject projects = 3;
ParticipantLocation location = 4;
uint32 participant_index = 5;
+ ChannelRole role = 6;
}
message PendingParticipant {
@@ -70,7 +70,7 @@ impl BufferSearchBar {
fn render_text_input(&self, editor: &View<Editor>, cx: &ViewContext<Self>) -> impl IntoElement {
let settings = ThemeSettings::get_global(cx);
let text_style = TextStyle {
- color: if editor.read(cx).read_only() {
+ color: if editor.read(cx).read_only(cx) {
cx.theme().colors().text_disabled
} else {
cx.theme().colors().text
@@ -223,6 +223,7 @@ impl Render for BufferSearchBar {
.gap_2()
.border_1()
.border_color(editor_border)
+ .min_w(rems(384. / 16.))
.rounded_lg()
.child(IconElement::new(Icon::MagnifyingGlass))
.child(self.render_text_input(&self.query_editor, cx))
@@ -422,89 +423,134 @@ impl ToolbarItemView for BufferSearchBar {
}
}
-impl BufferSearchBar {
- fn register(workspace: &mut Workspace) {
- workspace.register_action(move |workspace, deploy: &Deploy, cx| {
- let pane = workspace.active_pane();
+/// Registrar inverts the dependency between search and it's downstream user, allowing said downstream user to register search action without knowing exactly what those actions are.
+pub trait SearchActionsRegistrar {
+ fn register_handler<A: Action>(
+ &mut self,
+ callback: fn(&mut BufferSearchBar, &A, &mut ViewContext<BufferSearchBar>),
+ );
+}
+
+type GetSearchBar<T> =
+ for<'a, 'b> fn(&'a T, &'a mut ViewContext<'b, T>) -> Option<View<BufferSearchBar>>;
+
+/// Registers search actions on a div that can be taken out.
+pub struct DivRegistrar<'a, 'b, T: 'static> {
+ div: Option<Div>,
+ cx: &'a mut ViewContext<'b, T>,
+ search_getter: GetSearchBar<T>,
+}
+
+impl<'a, 'b, T: 'static> DivRegistrar<'a, 'b, T> {
+ pub fn new(search_getter: GetSearchBar<T>, cx: &'a mut ViewContext<'b, T>) -> Self {
+ Self {
+ div: Some(div()),
+ cx,
+ search_getter,
+ }
+ }
+ pub fn into_div(self) -> Div {
+ // This option is always Some; it's an option in the first place because we want to call methods
+ // on div that require ownership.
+ self.div.unwrap()
+ }
+}
+
+impl<T: 'static> SearchActionsRegistrar for DivRegistrar<'_, '_, T> {
+ fn register_handler<A: gpui::Action>(
+ &mut self,
+ callback: fn(&mut BufferSearchBar, &A, &mut ViewContext<BufferSearchBar>),
+ ) {
+ let getter = self.search_getter;
+ self.div = self.div.take().map(|div| {
+ div.on_action(self.cx.listener(move |this, action, cx| {
+ (getter)(this, cx)
+ .clone()
+ .map(|search_bar| search_bar.update(cx, |this, cx| callback(this, action, cx)));
+ }))
+ });
+ }
+}
- pane.update(cx, |this, cx| {
- this.toolbar().update(cx, |this, cx| {
+/// Register actions for an active pane.
+impl SearchActionsRegistrar for Workspace {
+ fn register_handler<A: Action>(
+ &mut self,
+ callback: fn(&mut BufferSearchBar, &A, &mut ViewContext<BufferSearchBar>),
+ ) {
+ self.register_action(move |workspace, action: &A, cx| {
+ let pane = workspace.active_pane();
+ pane.update(cx, move |this, cx| {
+ this.toolbar().update(cx, move |this, cx| {
if let Some(search_bar) = this.item_of_type::<BufferSearchBar>() {
- search_bar.update(cx, |this, cx| {
- this.deploy(deploy, cx);
- });
- return;
+ search_bar.update(cx, move |this, cx| callback(this, action, cx));
+ cx.notify();
}
- let view = cx.new_view(|cx| BufferSearchBar::new(cx));
- this.add_item(view.clone(), cx);
- view.update(cx, |this, cx| this.deploy(deploy, cx));
- cx.notify();
})
});
});
- fn register_action<A: Action>(
- workspace: &mut Workspace,
- update: fn(&mut BufferSearchBar, &A, &mut ViewContext<BufferSearchBar>),
- ) {
- workspace.register_action(move |workspace, action: &A, cx| {
- let pane = workspace.active_pane();
- pane.update(cx, move |this, cx| {
- this.toolbar().update(cx, move |this, cx| {
- if let Some(search_bar) = this.item_of_type::<BufferSearchBar>() {
- search_bar.update(cx, move |this, cx| update(this, action, cx));
- cx.notify();
- }
- })
- });
- });
- }
-
- register_action(workspace, |this, action: &ToggleCaseSensitive, cx| {
+ }
+}
+impl BufferSearchBar {
+ pub fn register_inner(registrar: &mut impl SearchActionsRegistrar) {
+ registrar.register_handler(|this, action: &ToggleCaseSensitive, cx| {
if this.supported_options().case {
this.toggle_case_sensitive(action, cx);
}
});
- register_action(workspace, |this, action: &ToggleWholeWord, cx| {
+
+ registrar.register_handler(|this, action: &ToggleWholeWord, cx| {
if this.supported_options().word {
this.toggle_whole_word(action, cx);
}
});
- register_action(workspace, |this, action: &ToggleReplace, cx| {
+
+ registrar.register_handler(|this, action: &ToggleReplace, cx| {
if this.supported_options().replacement {
this.toggle_replace(action, cx);
}
});
- register_action(workspace, |this, _: &ActivateRegexMode, cx| {
+
+ registrar.register_handler(|this, _: &ActivateRegexMode, cx| {
if this.supported_options().regex {
this.activate_search_mode(SearchMode::Regex, cx);
}
});
- register_action(workspace, |this, _: &ActivateTextMode, cx| {
+
+ registrar.register_handler(|this, _: &ActivateTextMode, cx| {
this.activate_search_mode(SearchMode::Text, cx);
});
- register_action(workspace, |this, action: &CycleMode, cx| {
+
+ registrar.register_handler(|this, action: &CycleMode, cx| {
if this.supported_options().regex {
// If regex is not supported then search has just one mode (text) - in that case there's no point in supporting
// cycling.
this.cycle_mode(action, cx)
}
});
- register_action(workspace, |this, action: &SelectNextMatch, cx| {
+
+ registrar.register_handler(|this, action: &SelectNextMatch, cx| {
this.select_next_match(action, cx);
});
- register_action(workspace, |this, action: &SelectPrevMatch, cx| {
+ registrar.register_handler(|this, action: &SelectPrevMatch, cx| {
this.select_prev_match(action, cx);
});
- register_action(workspace, |this, action: &SelectAllMatches, cx| {
+ registrar.register_handler(|this, action: &SelectAllMatches, cx| {
this.select_all_matches(action, cx);
});
- register_action(workspace, |this, _: &editor::Cancel, cx| {
+ registrar.register_handler(|this, _: &editor::Cancel, cx| {
if !this.dismissed {
this.dismiss(&Dismiss, cx);
return;
}
cx.propagate();
});
+ registrar.register_handler(|this, deploy, cx| {
+ this.deploy(deploy, cx);
+ })
+ }
+ fn register(workspace: &mut Workspace) {
+ Self::register_inner(workspace);
}
pub fn new(cx: &mut ViewContext<Self>) -> Self {
let query_editor = cx.new_view(|cx| Editor::single_line(cx));
@@ -38,8 +38,8 @@ use std::{
use theme::ThemeSettings;
use ui::{
- h_stack, prelude::*, v_stack, Button, Icon, IconButton, IconElement, Label, LabelCommon,
- LabelSize, Selectable, Tooltip,
+ h_stack, prelude::*, v_stack, Icon, IconButton, IconElement, Label, LabelCommon, LabelSize,
+ Selectable, ToggleButton, Tooltip,
};
use util::{paths::PathMatcher, ResultExt as _};
use workspace::{
@@ -61,12 +61,12 @@ struct ActiveSearches(HashMap<WeakModel<Project>, WeakView<ProjectSearchView>>);
struct ActiveSettings(HashMap<WeakModel<Project>, ProjectSearchSettings>);
pub fn init(cx: &mut AppContext) {
- // todo!() po
cx.set_global(ActiveSearches::default());
cx.set_global(ActiveSettings::default());
cx.observe_new_views(|workspace: &mut Workspace, _cx| {
workspace
- .register_action(ProjectSearchView::deploy)
+ .register_action(ProjectSearchView::new_search)
+ .register_action(ProjectSearchView::deploy_search)
.register_action(ProjectSearchBar::search_in_new);
})
.detach();
@@ -132,9 +132,11 @@ pub struct ProjectSearchBar {
impl ProjectSearch {
fn new(project: Model<Project>, cx: &mut ModelContext<Self>) -> Self {
let replica_id = project.read(cx).replica_id();
+ let capability = project.read(cx).capability();
+
Self {
project,
- excerpts: cx.new_model(|_| MultiBuffer::new(replica_id)),
+ excerpts: cx.new_model(|_| MultiBuffer::new(replica_id, capability)),
pending_search: Default::default(),
match_ranges: Default::default(),
active_query: None,
@@ -286,7 +288,6 @@ impl Render for ProjectSearchView {
.size_full()
.track_focus(&self.focus_handle)
.child(self.results_editor.clone())
- .into_any()
} else {
let model = self.model.read(cx);
let has_no_results = model.no_results.unwrap_or(false);
@@ -363,6 +364,7 @@ impl Render for ProjectSearchView {
.flex_1()
.size_full()
.justify_center()
+ .bg(cx.theme().colors().editor_background)
.track_focus(&self.focus_handle)
.child(
h_stack()
@@ -372,7 +374,6 @@ impl Render for ProjectSearchView {
.child(v_stack().child(major_text).children(minor_text))
.child(h_stack().flex_1()),
)
- .into_any()
}
}
}
@@ -941,11 +942,41 @@ impl ProjectSearchView {
});
}
+ // Re-activate the most recently activated search or the most recent if it has been closed.
+ // If no search exists in the workspace, create a new one.
+ fn deploy_search(
+ workspace: &mut Workspace,
+ _: &workspace::DeploySearch,
+ cx: &mut ViewContext<Workspace>,
+ ) {
+ let active_search = cx
+ .global::<ActiveSearches>()
+ .0
+ .get(&workspace.project().downgrade());
+ let existing = active_search
+ .and_then(|active_search| {
+ workspace
+ .items_of_type::<ProjectSearchView>(cx)
+ .filter(|search| &search.downgrade() == active_search)
+ .last()
+ })
+ .or_else(|| workspace.item_of_type::<ProjectSearchView>(cx));
+ Self::existing_or_new_search(workspace, existing, cx)
+ }
+
// Add another search tab to the workspace.
- fn deploy(
+ fn new_search(
workspace: &mut Workspace,
_: &workspace::NewSearch,
cx: &mut ViewContext<Workspace>,
+ ) {
+ Self::existing_or_new_search(workspace, None, cx)
+ }
+
+ fn existing_or_new_search(
+ workspace: &mut Workspace,
+ existing: Option<View<ProjectSearchView>>,
+ cx: &mut ViewContext<Workspace>,
) {
// Clean up entries for dropped projects
cx.update_global(|state: &mut ActiveSearches, _cx| {
@@ -962,19 +993,27 @@ impl ProjectSearchView {
}
});
- let settings = cx
- .global::<ActiveSettings>()
- .0
- .get(&workspace.project().downgrade());
-
- let settings = if let Some(settings) = settings {
- Some(settings.clone())
+ let search = if let Some(existing) = existing {
+ workspace.activate_item(&existing, cx);
+ existing
} else {
- None
- };
+ let settings = cx
+ .global::<ActiveSettings>()
+ .0
+ .get(&workspace.project().downgrade());
- let model = cx.new_model(|cx| ProjectSearch::new(workspace.project().clone(), cx));
- let search = cx.new_view(|cx| ProjectSearchView::new(model, cx, settings));
+ let settings = if let Some(settings) = settings {
+ Some(settings.clone())
+ } else {
+ None
+ };
+
+ let model = cx.new_model(|cx| ProjectSearch::new(workspace.project().clone(), cx));
+ let view = cx.new_view(|cx| ProjectSearchView::new(model, cx, settings));
+
+ workspace.add_item(Box::new(view.clone()), cx);
+ view
+ };
workspace.add_item(Box::new(search.clone()), cx);
@@ -1519,7 +1558,7 @@ impl ProjectSearchBar {
fn render_text_input(&self, editor: &View<Editor>, cx: &ViewContext<Self>) -> impl IntoElement {
let settings = ThemeSettings::get_global(cx);
let text_style = TextStyle {
- color: if editor.read(cx).read_only() {
+ color: if editor.read(cx).read_only(cx) {
cx.theme().colors().text_disabled
} else {
cx.theme().colors().text
@@ -1639,20 +1678,26 @@ impl Render for ProjectSearchBar {
let mode_column = v_stack().items_start().justify_start().child(
h_stack()
+ .gap_2()
.child(
h_stack()
.child(
- Button::new("project-search-text-button", "Text")
+ ToggleButton::new("project-search-text-button", "Text")
+ .style(ButtonStyle::Filled)
+ .size(ButtonSize::Large)
.selected(search.current_mode == SearchMode::Text)
.on_click(cx.listener(|this, _, cx| {
this.activate_search_mode(SearchMode::Text, cx)
}))
.tooltip(|cx| {
Tooltip::for_action("Toggle text search", &ActivateTextMode, cx)
- }),
+ })
+ .first(),
)
.child(
- Button::new("project-search-regex-button", "Regex")
+ ToggleButton::new("project-search-regex-button", "Regex")
+ .style(ButtonStyle::Filled)
+ .size(ButtonSize::Large)
.selected(search.current_mode == SearchMode::Regex)
.on_click(cx.listener(|this, _, cx| {
this.activate_search_mode(SearchMode::Regex, cx)
@@ -1663,11 +1708,20 @@ impl Render for ProjectSearchBar {
&ActivateRegexMode,
cx,
)
+ })
+ .map(|this| {
+ if semantic_is_available {
+ this.middle()
+ } else {
+ this.last()
+ }
}),
)
.when(semantic_is_available, |this| {
this.child(
- Button::new("project-search-semantic-button", "Semantic")
+ ToggleButton::new("project-search-semantic-button", "Semantic")
+ .style(ButtonStyle::Filled)
+ .size(ButtonSize::Large)
.selected(search.current_mode == SearchMode::Semantic)
.on_click(cx.listener(|this, _, cx| {
this.activate_search_mode(SearchMode::Semantic, cx)
@@ -1678,7 +1732,8 @@ impl Render for ProjectSearchBar {
&ActivateSemanticMode,
cx,
)
- }),
+ })
+ .last(),
)
}),
)
@@ -1829,6 +1884,7 @@ impl Render for ProjectSearchBar {
.child(
h_stack()
.justify_between()
+ .gap_2()
.child(query_column)
.child(mode_column)
.child(replace_column)
@@ -2060,7 +2116,237 @@ pub mod tests {
}
#[gpui::test]
- async fn test_project_search_focus(cx: &mut TestAppContext) {
+ async fn test_deploy_project_search_focus(cx: &mut TestAppContext) {
+ init_test(cx);
+
+ let fs = FakeFs::new(cx.background_executor.clone());
+ fs.insert_tree(
+ "/dir",
+ json!({
+ "one.rs": "const ONE: usize = 1;",
+ "two.rs": "const TWO: usize = one::ONE + one::ONE;",
+ "three.rs": "const THREE: usize = one::ONE + two::TWO;",
+ "four.rs": "const FOUR: usize = one::ONE + three::THREE;",
+ }),
+ )
+ .await;
+ let project = Project::test(fs.clone(), ["/dir".as_ref()], cx).await;
+ let window = cx.add_window(|cx| Workspace::test_new(project, cx));
+ let workspace = window.clone();
+ let search_bar = window.build_view(cx, |_| ProjectSearchBar::new());
+
+ let active_item = cx.read(|cx| {
+ workspace
+ .read(cx)
+ .unwrap()
+ .active_pane()
+ .read(cx)
+ .active_item()
+ .and_then(|item| item.downcast::<ProjectSearchView>())
+ });
+ assert!(
+ active_item.is_none(),
+ "Expected no search panel to be active"
+ );
+
+ window
+ .update(cx, move |workspace, cx| {
+ assert_eq!(workspace.panes().len(), 1);
+ workspace.panes()[0].update(cx, move |pane, cx| {
+ pane.toolbar()
+ .update(cx, |toolbar, cx| toolbar.add_item(search_bar, cx))
+ });
+
+ ProjectSearchView::deploy_search(workspace, &workspace::DeploySearch, cx)
+ })
+ .unwrap();
+
+ let Some(search_view) = cx.read(|cx| {
+ workspace
+ .read(cx)
+ .unwrap()
+ .active_pane()
+ .read(cx)
+ .active_item()
+ .and_then(|item| item.downcast::<ProjectSearchView>())
+ }) else {
+ panic!("Search view expected to appear after new search event trigger")
+ };
+
+ cx.spawn(|mut cx| async move {
+ window
+ .update(&mut cx, |_, cx| {
+ cx.dispatch_action(ToggleFocus.boxed_clone())
+ })
+ .unwrap();
+ })
+ .detach();
+ cx.background_executor.run_until_parked();
+ window
+ .update(cx, |_, cx| {
+ search_view.update(cx, |search_view, cx| {
+ assert!(
+ search_view.query_editor.focus_handle(cx).is_focused(cx),
+ "Empty search view should be focused after the toggle focus event: no results panel to focus on",
+ );
+ });
+ }).unwrap();
+
+ window
+ .update(cx, |_, cx| {
+ search_view.update(cx, |search_view, cx| {
+ let query_editor = &search_view.query_editor;
+ assert!(
+ query_editor.focus_handle(cx).is_focused(cx),
+ "Search view should be focused after the new search view is activated",
+ );
+ let query_text = query_editor.read(cx).text(cx);
+ assert!(
+ query_text.is_empty(),
+ "New search query should be empty but got '{query_text}'",
+ );
+ let results_text = search_view
+ .results_editor
+ .update(cx, |editor, cx| editor.display_text(cx));
+ assert!(
+ results_text.is_empty(),
+ "Empty search view should have no results but got '{results_text}'"
+ );
+ });
+ })
+ .unwrap();
+
+ window
+ .update(cx, |_, cx| {
+ search_view.update(cx, |search_view, cx| {
+ search_view.query_editor.update(cx, |query_editor, cx| {
+ query_editor.set_text("sOMETHINGtHATsURELYdOESnOTeXIST", cx)
+ });
+ search_view.search(cx);
+ });
+ })
+ .unwrap();
+ cx.background_executor.run_until_parked();
+ window
+ .update(cx, |_, cx| {
+ search_view.update(cx, |search_view, cx| {
+ let results_text = search_view
+ .results_editor
+ .update(cx, |editor, cx| editor.display_text(cx));
+ assert!(
+ results_text.is_empty(),
+ "Search view for mismatching query should have no results but got '{results_text}'"
+ );
+ assert!(
+ search_view.query_editor.focus_handle(cx).is_focused(cx),
+ "Search view should be focused after mismatching query had been used in search",
+ );
+ });
+ }).unwrap();
+
+ cx.spawn(|mut cx| async move {
+ window.update(&mut cx, |_, cx| {
+ cx.dispatch_action(ToggleFocus.boxed_clone())
+ })
+ })
+ .detach();
+ cx.background_executor.run_until_parked();
+ window.update(cx, |_, cx| {
+ search_view.update(cx, |search_view, cx| {
+ assert!(
+ search_view.query_editor.focus_handle(cx).is_focused(cx),
+ "Search view with mismatching query should be focused after the toggle focus event: still no results panel to focus on",
+ );
+ });
+ }).unwrap();
+
+ window
+ .update(cx, |_, cx| {
+ search_view.update(cx, |search_view, cx| {
+ search_view
+ .query_editor
+ .update(cx, |query_editor, cx| query_editor.set_text("TWO", cx));
+ search_view.search(cx);
+ });
+ })
+ .unwrap();
+ cx.background_executor.run_until_parked();
+ window.update(cx, |_, cx| {
+ search_view.update(cx, |search_view, cx| {
+ assert_eq!(
+ search_view
+ .results_editor
+ .update(cx, |editor, cx| editor.display_text(cx)),
+ "\n\nconst THREE: usize = one::ONE + two::TWO;\n\n\nconst TWO: usize = one::ONE + one::ONE;",
+ "Search view results should match the query"
+ );
+ assert!(
+ search_view.results_editor.focus_handle(cx).is_focused(cx),
+ "Search view with mismatching query should be focused after search results are available",
+ );
+ });
+ }).unwrap();
+ cx.spawn(|mut cx| async move {
+ window
+ .update(&mut cx, |_, cx| {
+ cx.dispatch_action(ToggleFocus.boxed_clone())
+ })
+ .unwrap();
+ })
+ .detach();
+ cx.background_executor.run_until_parked();
+ window.update(cx, |_, cx| {
+ search_view.update(cx, |search_view, cx| {
+ assert!(
+ search_view.results_editor.focus_handle(cx).is_focused(cx),
+ "Search view with matching query should still have its results editor focused after the toggle focus event",
+ );
+ });
+ }).unwrap();
+
+ workspace
+ .update(cx, |workspace, cx| {
+ ProjectSearchView::deploy_search(workspace, &workspace::DeploySearch, cx)
+ })
+ .unwrap();
+ window.update(cx, |_, cx| {
+ search_view.update(cx, |search_view, cx| {
+ assert_eq!(search_view.query_editor.read(cx).text(cx), "two", "Query should be updated to first search result after search view 2nd open in a row");
+ assert_eq!(
+ search_view
+ .results_editor
+ .update(cx, |editor, cx| editor.display_text(cx)),
+ "\n\nconst THREE: usize = one::ONE + two::TWO;\n\n\nconst TWO: usize = one::ONE + one::ONE;",
+ "Results should be unchanged after search view 2nd open in a row"
+ );
+ assert!(
+ search_view.query_editor.focus_handle(cx).is_focused(cx),
+ "Focus should be moved into query editor again after search view 2nd open in a row"
+ );
+ });
+ }).unwrap();
+
+ cx.spawn(|mut cx| async move {
+ window
+ .update(&mut cx, |_, cx| {
+ cx.dispatch_action(ToggleFocus.boxed_clone())
+ })
+ .unwrap();
+ })
+ .detach();
+ cx.background_executor.run_until_parked();
+ window.update(cx, |_, cx| {
+ search_view.update(cx, |search_view, cx| {
+ assert!(
+ search_view.results_editor.focus_handle(cx).is_focused(cx),
+ "Search view with matching query should switch focus to the results editor after the toggle focus event",
+ );
+ });
+ }).unwrap();
+ }
+
+ #[gpui::test]
+ async fn test_new_project_search_focus(cx: &mut TestAppContext) {
init_test(cx);
let fs = FakeFs::new(cx.background_executor.clone());
@@ -2101,7 +2387,7 @@ pub mod tests {
.update(cx, |toolbar, cx| toolbar.add_item(search_bar, cx))
});
- ProjectSearchView::deploy(workspace, &workspace::NewSearch, cx)
+ ProjectSearchView::new_search(workspace, &workspace::NewSearch, cx)
})
.unwrap();
@@ -2250,7 +2536,7 @@ pub mod tests {
workspace
.update(cx, |workspace, cx| {
- ProjectSearchView::deploy(workspace, &workspace::NewSearch, cx)
+ ProjectSearchView::new_search(workspace, &workspace::NewSearch, cx)
})
.unwrap();
cx.background_executor.run_until_parked();
@@ -2536,7 +2822,7 @@ pub mod tests {
.update(cx, |toolbar, cx| toolbar.add_item(search_bar, cx))
});
- ProjectSearchView::deploy(workspace, &workspace::NewSearch, cx)
+ ProjectSearchView::new_search(workspace, &workspace::NewSearch, cx)
}
})
.unwrap();
@@ -14,7 +14,6 @@ test-support = ["gpui/test-support", "fs/test-support"]
[dependencies]
collections = { path = "../collections" }
gpui = { path = "../gpui" }
-sqlez = { path = "../sqlez" }
fs = { path = "../fs" }
feature_flags = { path = "../feature_flags" }
util = { path = "../util" }
@@ -1,4 +1,4 @@
-use crate::{settings_store::SettingsStore, KeymapFile, Settings};
+use crate::{settings_store::SettingsStore, Settings};
use anyhow::Result;
use fs::Fs;
use futures::{channel::mpsc, StreamExt};
@@ -77,7 +77,6 @@ pub fn handle_settings_file_changes(
});
cx.spawn(move |mut cx| async move {
while let Some(user_settings_content) = user_settings_file_rx.next().await {
- eprintln!("settings file changed");
let result = cx.update_global(|store: &mut SettingsStore, cx| {
store
.set_user_settings(&user_settings_content, cx)
@@ -121,14 +120,3 @@ pub fn update_settings_file<T: Settings>(
})
.detach_and_log_err(cx);
}
-
-pub fn load_default_keymap(cx: &mut AppContext) {
- for path in ["keymaps/default.json", "keymaps/vim.json"] {
- KeymapFile::load_asset(path, cx).unwrap();
- }
-
- // todo!()
- // if let Some(asset_path) = settings::get::<BaseKeymap>(cx).asset_path() {
- // KeymapFile::load_asset(asset_path, cx).unwrap();
- // }
-}
@@ -158,39 +158,41 @@ pub fn mouse_moved_report(point: AlacPoint, e: &MouseMoveEvent, mode: TermMode)
}
}
-pub fn mouse_side(
+pub fn grid_point(pos: Point<Pixels>, cur_size: TerminalSize, display_offset: usize) -> AlacPoint {
+ grid_point_and_side(pos, cur_size, display_offset).0
+}
+
+pub fn grid_point_and_side(
pos: Point<Pixels>,
cur_size: TerminalSize,
-) -> alacritty_terminal::index::Direction {
- let cell_width = cur_size.cell_width.floor();
- if cell_width == px(0.) {
- return Side::Right;
- }
-
- let x = pos.x.floor();
-
- let cell_x = cmp::max(px(0.), x - cell_width) % cell_width;
- let half_cell_width = (cur_size.cell_width / 2.0).floor();
- let additional_padding = (cur_size.width() - cur_size.cell_width * 2.) % cur_size.cell_width;
- let end_of_grid = cur_size.width() - cur_size.cell_width - additional_padding;
-
- //Width: Pixels or columns?
- if cell_x > half_cell_width
- // Edge case when mouse leaves the window.
- || x >= end_of_grid
- {
+ display_offset: usize,
+) -> (AlacPoint, Side) {
+ let mut col = GridCol((pos.x / cur_size.cell_width) as usize);
+ let cell_x = cmp::max(px(0.), pos.x) % cur_size.cell_width;
+ let half_cell_width = cur_size.cell_width / 2.0;
+ let mut side = if cell_x > half_cell_width {
Side::Right
} else {
Side::Left
- }
-}
+ };
-pub fn grid_point(pos: Point<Pixels>, cur_size: TerminalSize, display_offset: usize) -> AlacPoint {
- let col = GridCol((pos.x / cur_size.cell_width) as usize);
+ if col > cur_size.last_column() {
+ col = cur_size.last_column();
+ side = Side::Right;
+ }
let col = min(col, cur_size.last_column());
- let line = (pos.y / cur_size.line_height) as i32;
- let line = min(line, cur_size.bottommost_line().0);
- AlacPoint::new(GridLine(line - display_offset as i32), col)
+ let mut line = (pos.y / cur_size.line_height) as i32;
+ if line > cur_size.bottommost_line() {
+ line = cur_size.bottommost_line().0 as i32;
+ side = Side::Right;
+ } else if line < 0 {
+ side = Side::Left;
+ }
+
+ (
+ AlacPoint::new(GridLine(line - display_offset as i32), col),
+ side,
+ )
}
///Generate the bytes to send to the terminal, from the cell location, a mouse event, and the terminal mode
@@ -28,7 +28,8 @@ use futures::{
};
use mappings::mouse::{
- alt_scroll, grid_point, mouse_button_report, mouse_moved_report, mouse_side, scroll_report,
+ alt_scroll, grid_point, grid_point_and_side, mouse_button_report, mouse_moved_report,
+ scroll_report,
};
use procinfo::LocalProcessInfo;
@@ -61,15 +62,7 @@ use lazy_static::lazy_static;
actions!(
terminal,
- [
- Clear,
- Copy,
- Paste,
- ShowCharacterPalette,
- SearchTest,
- SendText,
- SendKeystroke,
- ]
+ [Clear, Copy, Paste, ShowCharacterPalette, SearchTest,]
);
///Scrolling is unbearably sluggish by default. Alacritty supports a configurable
@@ -704,14 +697,12 @@ impl Terminal {
}
InternalEvent::UpdateSelection(position) => {
if let Some(mut selection) = term.selection.take() {
- let point = grid_point(
+ let (point, side) = grid_point_and_side(
*position,
self.last_content.size,
term.grid().display_offset(),
);
- let side = mouse_side(*position, self.last_content.size);
-
selection.update(point, side);
term.selection = Some(selection);
@@ -1088,12 +1079,11 @@ impl Terminal {
let position = e.position - origin;
self.last_mouse_position = Some(position);
if self.mouse_mode(e.modifiers.shift) {
- let point = grid_point(
+ let (point, side) = grid_point_and_side(
position,
self.last_content.size,
self.last_content.display_offset,
);
- let side = mouse_side(position, self.last_content.size);
if self.mouse_changed(point, side) {
if let Some(bytes) = mouse_moved_report(point, e, self.last_content.mode) {
@@ -1175,15 +1165,12 @@ impl Terminal {
}
} else if e.button == MouseButton::Left {
let position = e.position - origin;
- let point = grid_point(
+ let (point, side) = grid_point_and_side(
position,
self.last_content.size,
self.last_content.display_offset,
);
- // Use .opposite so that selection is inclusive of the cell clicked.
- let side = mouse_side(position, self.last_content.size);
-
let selection_type = match e.click_count {
0 => return, //This is a release
1 => Some(SelectionType::Simple),
@@ -13,7 +13,7 @@ editor = { path = "../editor" }
language = { path = "../language" }
gpui = { path = "../gpui" }
project = { path = "../project" }
-# search = { path = "../search" }
+search = { path = "../search" }
settings = { path = "../settings" }
theme = { path = "../theme" }
util = { path = "../util" }
@@ -2,10 +2,11 @@ use editor::{Cursor, HighlightedRange, HighlightedRangeLine};
use gpui::{
div, fill, point, px, red, relative, AnyElement, AsyncWindowContext, AvailableSpace,
BorrowWindow, Bounds, DispatchPhase, Element, ElementId, ExternalPaths, FocusHandle, Font,
- FontStyle, FontWeight, HighlightStyle, Hsla, InteractiveElement, InteractiveElementState,
- Interactivity, IntoElement, LayoutId, Model, ModelContext, ModifiersChangedEvent, MouseButton,
- Pixels, PlatformInputHandler, Point, ShapedLine, StatefulInteractiveElement, StyleRefinement,
- Styled, TextRun, TextStyle, TextSystem, UnderlineStyle, WhiteSpace, WindowContext,
+ FontStyle, FontWeight, HighlightStyle, Hsla, InteractiveBounds, InteractiveElement,
+ InteractiveElementState, Interactivity, IntoElement, LayoutId, Model, ModelContext,
+ ModifiersChangedEvent, MouseButton, MouseMoveEvent, Pixels, PlatformInputHandler, Point,
+ ShapedLine, StatefulInteractiveElement, StyleRefinement, Styled, TextRun, TextStyle,
+ TextSystem, UnderlineStyle, WhiteSpace, WindowContext,
};
use itertools::Itertools;
use language::CursorShape;
@@ -421,7 +422,7 @@ impl TerminalElement {
let rem_size = cx.rem_size();
let font_pixels = text_style.font_size.to_pixels(rem_size);
let line_height = font_pixels * line_height.to_pixels(rem_size);
- let font_id = cx.text_system().font_id(&text_style.font()).unwrap();
+ let font_id = cx.text_system().resolve_font(&text_style.font());
// todo!(do we need to keep this unwrap?)
let cell_width = text_system
@@ -598,33 +599,48 @@ impl TerminalElement {
) {
let focus = self.focus.clone();
let terminal = self.terminal.clone();
+ let interactive_bounds = InteractiveBounds {
+ bounds: bounds.intersect(&cx.content_mask().bounds),
+ stacking_order: cx.stacking_order().clone(),
+ };
self.interactivity.on_mouse_down(MouseButton::Left, {
let terminal = terminal.clone();
let focus = focus.clone();
move |e, cx| {
cx.focus(&focus);
- //todo!(context menu)
- // v.context_menu.update(cx, |menu, _cx| menu.delay_cancel());
terminal.update(cx, |terminal, cx| {
terminal.mouse_down(&e, origin);
-
cx.notify();
})
}
});
- self.interactivity.on_mouse_move({
- let terminal = terminal.clone();
- let focus = focus.clone();
- move |e, cx| {
- if e.pressed_button.is_some() && focus.is_focused(cx) && !cx.has_active_drag() {
+
+ cx.on_mouse_event({
+ let bounds = bounds.clone();
+ let focus = self.focus.clone();
+ let terminal = self.terminal.clone();
+ move |e: &MouseMoveEvent, phase, cx| {
+ if phase != DispatchPhase::Bubble || !focus.is_focused(cx) {
+ return;
+ }
+
+ if e.pressed_button.is_some() && !cx.has_active_drag() {
terminal.update(cx, |terminal, cx| {
terminal.mouse_drag(e, origin, bounds);
cx.notify();
})
}
+
+ if interactive_bounds.visibly_contains(&e.position, cx) {
+ terminal.update(cx, |terminal, cx| {
+ terminal.mouse_move(&e, origin);
+ cx.notify();
+ })
+ }
}
});
+
self.interactivity.on_mouse_up(
MouseButton::Left,
TerminalElement::generic_button_handler(
@@ -651,19 +667,6 @@ impl TerminalElement {
}
}
});
-
- self.interactivity.on_mouse_move({
- let terminal = terminal.clone();
- let focus = focus.clone();
- move |e, cx| {
- if focus.is_focused(cx) {
- terminal.update(cx, |terminal, cx| {
- terminal.mouse_move(&e, origin);
- cx.notify();
- })
- }
- }
- });
self.interactivity.on_scroll_wheel({
let terminal = terminal.clone();
move |e, cx| {
@@ -3,11 +3,12 @@ use std::{path::PathBuf, sync::Arc};
use crate::TerminalView;
use db::kvp::KEY_VALUE_STORE;
use gpui::{
- actions, div, serde_json, AppContext, AsyncWindowContext, Entity, EventEmitter, ExternalPaths,
+ actions, serde_json, AppContext, AsyncWindowContext, Entity, EventEmitter, ExternalPaths,
FocusHandle, FocusableView, IntoElement, ParentElement, Pixels, Render, Styled, Subscription,
Task, View, ViewContext, VisualContext, WeakView, WindowContext,
};
use project::Fs;
+use search::{buffer_search::DivRegistrar, BufferSearchBar};
use serde::{Deserialize, Serialize};
use settings::{Settings, SettingsStore};
use terminal::terminal_settings::{TerminalDockPosition, TerminalSettings};
@@ -52,7 +53,7 @@ pub struct TerminalPanel {
impl TerminalPanel {
fn new(workspace: &Workspace, cx: &mut ViewContext<Self>) -> Self {
- let terminal_panel = cx.view().clone();
+ let terminal_panel = cx.view().downgrade();
let pane = cx.new_view(|cx| {
let mut pane = Pane::new(
workspace.weak_handle(),
@@ -76,14 +77,17 @@ impl TerminalPanel {
pane.set_can_navigate(false, cx);
pane.display_nav_history_buttons(false);
pane.set_render_tab_bar_buttons(cx, move |pane, cx| {
+ let terminal_panel = terminal_panel.clone();
h_stack()
.gap_2()
.child(
IconButton::new("plus", Icon::Plus)
.icon_size(IconSize::Small)
- .on_click(cx.listener_for(&terminal_panel, |terminal_panel, _, cx| {
- terminal_panel.add_terminal(None, cx);
- }))
+ .on_click(move |_, cx| {
+ terminal_panel
+ .update(cx, |panel, cx| panel.add_terminal(None, cx))
+ .log_err();
+ })
.tooltip(|cx| Tooltip::text("New Terminal", cx)),
)
.child({
@@ -101,9 +105,9 @@ impl TerminalPanel {
})
.into_any_element()
});
- // let buffer_search_bar = cx.build_view(search::BufferSearchBar::new);
- // pane.toolbar()
- // .update(cx, |toolbar, cx| toolbar.add_item(buffer_search_bar, cx));
+ let buffer_search_bar = cx.new_view(search::BufferSearchBar::new);
+ pane.toolbar()
+ .update(cx, |toolbar, cx| toolbar.add_item(buffer_search_bar, cx));
pane
});
let subscriptions = vec![
@@ -329,8 +333,20 @@ impl TerminalPanel {
impl EventEmitter<PanelEvent> for TerminalPanel {}
impl Render for TerminalPanel {
- fn render(&mut self, _cx: &mut ViewContext<Self>) -> impl IntoElement {
- div().size_full().child(self.pane.clone())
+ fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
+ let mut registrar = DivRegistrar::new(
+ |panel, cx| {
+ panel
+ .pane
+ .read(cx)
+ .toolbar()
+ .read(cx)
+ .item_of_type::<BufferSearchBar>()
+ },
+ cx,
+ );
+ BufferSearchBar::register_inner(&mut registrar);
+ registrar.into_div().size_full().child(self.pane.clone())
}
}
@@ -410,11 +426,6 @@ impl Panel for TerminalPanel {
"TerminalPanel"
}
- // todo!()
- // fn icon_tooltip(&self) -> (String, Option<Box<dyn Action>>) {
- // ("Terminal Panel".into(), Some(Box::new(ToggleFocus)))
- // }
-
fn icon(&self, _cx: &WindowContext) -> Option<Icon> {
Some(Icon::Terminal)
}
@@ -28,7 +28,7 @@ use workspace::{
item::{BreadcrumbText, Item, ItemEvent},
notifications::NotifyResultExt,
register_deserializable_item,
- searchable::{SearchEvent, SearchOptions, SearchableItem},
+ searchable::{SearchEvent, SearchOptions, SearchableItem, SearchableItemHandle},
CloseActiveItem, NewCenterTerminal, Pane, ToolbarItemLocation, Workspace, WorkspaceId,
};
@@ -57,7 +57,7 @@ pub struct SendText(String);
#[derive(Clone, Debug, Default, Deserialize, PartialEq)]
pub struct SendKeystroke(String);
-impl_actions!(terminal_view, [SendText, SendKeystroke]);
+impl_actions!(terminal, [SendText, SendKeystroke]);
pub fn init(cx: &mut AppContext) {
terminal_panel::init(cx);
@@ -714,10 +714,9 @@ impl Item for TerminalView {
false
}
- // todo!(search)
- // fn as_searchable(&self, handle: &View<Self>) -> Option<Box<dyn SearchableItemHandle>> {
- // Some(Box::new(handle.clone()))
- // }
+ fn as_searchable(&self, handle: &View<Self>) -> Option<Box<dyn SearchableItemHandle>> {
+ Some(Box::new(handle.clone()))
+ }
fn breadcrumb_location(&self) -> ToolbarItemLocation {
ToolbarItemLocation::PrimaryLeft
@@ -131,6 +131,15 @@ impl PlayerColors {
*self.0.last().unwrap()
}
+ pub fn read_only(&self) -> PlayerColor {
+ let local = self.local();
+ PlayerColor {
+ cursor: local.cursor.grayscale(),
+ background: local.background.grayscale(),
+ selection: local.selection.grayscale(),
+ }
+ }
+
pub fn color_for_participant(&self, participant_index: u32) -> PlayerColor {
let len = self.0.len() - 1;
self.0[(participant_index as usize % len) + 1]
@@ -0,0 +1,1013 @@
+## [Andromeda](https://github.com/EliverLara/Andromeda)
+
+The MIT License (MIT)
+
+Copyright (c) 2017 <eliverlara@gmail.com>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+********************************************************************************
+
+## [Atelier Cave Dark](https://atelierbram.github.io/syntax-highlighting/atelier-schemes/cave/)
+
+The MIT License (MIT)
+
+Copyright (c) 2023 Bram de Haan, http://atelierbramdehaan.nl
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+********************************************************************************
+
+## [Atelier Cave Light](https://atelierbram.github.io/syntax-highlighting/atelier-schemes/cave/)
+
+The MIT License (MIT)
+
+Copyright (c) 2023 Bram de Haan, http://atelierbramdehaan.nl
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+********************************************************************************
+
+## [Atelier Dune Dark](https://atelierbram.github.io/syntax-highlighting/atelier-schemes/cave/)
+
+The MIT License (MIT)
+
+Copyright (c) 2023 Bram de Haan, http://atelierbramdehaan.nl
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+********************************************************************************
+
+## [Atelier Dune Light](https://atelierbram.github.io/syntax-highlighting/atelier-schemes/cave/)
+
+The MIT License (MIT)
+
+Copyright (c) 2023 Bram de Haan, http://atelierbramdehaan.nl
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+********************************************************************************
+
+## [Atelier Estuary Dark](https://atelierbram.github.io/syntax-highlighting/atelier-schemes/cave/)
+
+The MIT License (MIT)
+
+Copyright (c) 2023 Bram de Haan, http://atelierbramdehaan.nl
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+********************************************************************************
+
+## [Atelier Estuary Light](https://atelierbram.github.io/syntax-highlighting/atelier-schemes/cave/)
+
+The MIT License (MIT)
+
+Copyright (c) 2023 Bram de Haan, http://atelierbramdehaan.nl
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+********************************************************************************
+
+## [Atelier Forest Dark](https://atelierbram.github.io/syntax-highlighting/atelier-schemes/cave/)
+
+The MIT License (MIT)
+
+Copyright (c) 2023 Bram de Haan, http://atelierbramdehaan.nl
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+********************************************************************************
+
+## [Atelier Forest Light](https://atelierbram.github.io/syntax-highlighting/atelier-schemes/cave/)
+
+The MIT License (MIT)
+
+Copyright (c) 2023 Bram de Haan, http://atelierbramdehaan.nl
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+********************************************************************************
+
+## [Atelier Heath Dark](https://atelierbram.github.io/syntax-highlighting/atelier-schemes/cave/)
+
+The MIT License (MIT)
+
+Copyright (c) 2023 Bram de Haan, http://atelierbramdehaan.nl
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+********************************************************************************
+
+## [Atelier Heath Light](https://atelierbram.github.io/syntax-highlighting/atelier-schemes/cave/)
+
+The MIT License (MIT)
+
+Copyright (c) 2023 Bram de Haan, http://atelierbramdehaan.nl
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+********************************************************************************
+
+## [Atelier Lakeside Dark](https://atelierbram.github.io/syntax-highlighting/atelier-schemes/cave/)
+
+The MIT License (MIT)
+
+Copyright (c) 2023 Bram de Haan, http://atelierbramdehaan.nl
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+********************************************************************************
+
+## [Atelier Lakeside Light](https://atelierbram.github.io/syntax-highlighting/atelier-schemes/cave/)
+
+The MIT License (MIT)
+
+Copyright (c) 2023 Bram de Haan, http://atelierbramdehaan.nl
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+********************************************************************************
+
+## [Atelier Plateau Dark](https://atelierbram.github.io/syntax-highlighting/atelier-schemes/cave/)
+
+The MIT License (MIT)
+
+Copyright (c) 2023 Bram de Haan, http://atelierbramdehaan.nl
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+********************************************************************************
+
+## [Atelier Plateau Light](https://atelierbram.github.io/syntax-highlighting/atelier-schemes/cave/)
+
+The MIT License (MIT)
+
+Copyright (c) 2023 Bram de Haan, http://atelierbramdehaan.nl
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+********************************************************************************
+
+## [Atelier Savanna Dark](https://atelierbram.github.io/syntax-highlighting/atelier-schemes/cave/)
+
+The MIT License (MIT)
+
+Copyright (c) 2023 Bram de Haan, http://atelierbramdehaan.nl
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+********************************************************************************
+
+## [Atelier Savanna Light](https://atelierbram.github.io/syntax-highlighting/atelier-schemes/cave/)
+
+The MIT License (MIT)
+
+Copyright (c) 2023 Bram de Haan, http://atelierbramdehaan.nl
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+********************************************************************************
+
+## [Atelier Seaside Dark](https://atelierbram.github.io/syntax-highlighting/atelier-schemes/cave/)
+
+The MIT License (MIT)
+
+Copyright (c) 2023 Bram de Haan, http://atelierbramdehaan.nl
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+********************************************************************************
+
+## [Atelier Seaside Light](https://atelierbram.github.io/syntax-highlighting/atelier-schemes/cave/)
+
+The MIT License (MIT)
+
+Copyright (c) 2023 Bram de Haan, http://atelierbramdehaan.nl
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+********************************************************************************
+
+## [Atelier Sulphurpool Dark](https://atelierbram.github.io/syntax-highlighting/atelier-schemes/cave/)
+
+The MIT License (MIT)
+
+Copyright (c) 2023 Bram de Haan, http://atelierbramdehaan.nl
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+********************************************************************************
+
+## [Atelier Sulphurpool Light](https://atelierbram.github.io/syntax-highlighting/atelier-schemes/cave/)
+
+The MIT License (MIT)
+
+Copyright (c) 2023 Bram de Haan, http://atelierbramdehaan.nl
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+********************************************************************************
+
+## [Ayu Dark](https://github.com/dempfi/ayu)
+
+The MIT License (MIT)
+
+Copyright (c) 2016 Ike Ku
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+********************************************************************************
+
+## [Ayu Light](https://github.com/dempfi/ayu)
+
+The MIT License (MIT)
+
+Copyright (c) 2016 Ike Ku
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+********************************************************************************
+
+## [Ayu Mirage](https://github.com/dempfi/ayu)
+
+The MIT License (MIT)
+
+Copyright (c) 2016 Ike Ku
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+********************************************************************************
+
+## [Gruvbox Dark](https://github.com/morhetz/gruvbox)
+
+The MIT License (MIT)
+
+Copyright (c) <YEAR> <COPYRIGHT HOLDER>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+********************************************************************************
+
+## [Gruvbox Dark Hard](https://github.com/morhetz/gruvbox)
+
+The MIT License (MIT)
+
+Copyright (c) <YEAR> <COPYRIGHT HOLDER>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+********************************************************************************
+
+## [Gruvbox Dark Soft](https://github.com/morhetz/gruvbox)
+
+The MIT License (MIT)
+
+Copyright (c) <YEAR> <COPYRIGHT HOLDER>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+********************************************************************************
+
+## [Gruvbox Light](https://github.com/morhetz/gruvbox)
+
+The MIT License (MIT)
+
+Copyright (c) <YEAR> <COPYRIGHT HOLDER>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+********************************************************************************
+
+## [Gruvbox Light Hard](https://github.com/morhetz/gruvbox)
+
+The MIT License (MIT)
+
+Copyright (c) <YEAR> <COPYRIGHT HOLDER>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+********************************************************************************
+
+## [Gruvbox Light Soft](https://github.com/morhetz/gruvbox)
+
+The MIT License (MIT)
+
+Copyright (c) <YEAR> <COPYRIGHT HOLDER>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+********************************************************************************
+
+## [One Dark](https://github.com/atom/atom/tree/master/packages/one-dark-ui)
+
+The MIT License (MIT)
+
+Copyright (c) 2014 GitHub Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+********************************************************************************
+
+## [One Light](https://github.com/atom/atom/tree/master/packages/one-light-ui)
+
+The MIT License (MIT)
+
+Copyright (c) 2014 GitHub Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+********************************************************************************
+
+## [Rosé Pine](https://github.com/edunfelt/base16-rose-pine-scheme)
+
+The MIT License (MIT)
+
+Copyright (c) 2021 Emilia Dunfelt
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+********************************************************************************
+
+## [Rosé Pine Dawn](https://github.com/edunfelt/base16-rose-pine-scheme)
+
+The MIT License (MIT)
+
+Copyright (c) 2021 Emilia Dunfelt
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+********************************************************************************
+
+## [Rosé Pine Moon](https://github.com/edunfelt/base16-rose-pine-scheme)
+
+The MIT License (MIT)
+
+Copyright (c) 2021 Emilia Dunfelt
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+********************************************************************************
+
+## [Sandcastle](https://github.com/gessig/base16-sandcastle-scheme)
+
+The MIT License (MIT)
+
+Copyright (c) 2019 George Essig
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+********************************************************************************
+
+## [Solarized Dark](https://github.com/altercation/solarized)
+
+The MIT License (MIT)
+
+Copyright (c) 2011 Ethan Schoonover
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+********************************************************************************
+
+## [Solarized Light](https://github.com/altercation/solarized)
+
+The MIT License (MIT)
+
+Copyright (c) 2011 Ethan Schoonover
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+********************************************************************************
+
+## [Summercamp](https://github.com/zoefiri/base16-sc)
+
+The MIT License (MIT)
+
+Copyright (c) 2019 Zoe FiriH
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+********************************************************************************
@@ -16,170 +16,170 @@ pub fn atelier() -> UserThemeFamily {
author: "Zed Industries".into(),
themes: vec![
UserTheme {
- name: "Atelier Estuary Light".into(),
- appearance: Appearance::Light,
+ name: "Atelier Cave Dark".into(),
+ appearance: Appearance::Dark,
styles: UserThemeStylesRefinement {
colors: ThemeColorsRefinement {
- border: Some(rgba(0x969585ff).into()),
- border_variant: Some(rgba(0xd1d0c6ff).into()),
- border_focused: Some(rgba(0xbbddc6ff).into()),
- border_selected: Some(rgba(0xbbddc6ff).into()),
+ border: Some(rgba(0x56505eff).into()),
+ border_variant: Some(rgba(0x332f38ff).into()),
+ border_focused: Some(rgba(0x222953ff).into()),
+ border_selected: Some(rgba(0x222953ff).into()),
border_transparent: Some(rgba(0x00000000).into()),
- border_disabled: Some(rgba(0xadac9fff).into()),
- elevated_surface_background: Some(rgba(0xebeae3ff).into()),
- surface_background: Some(rgba(0xebeae3ff).into()),
- background: Some(rgba(0xc5c4b9ff).into()),
- panel_background: Some(rgba(0xebeae3ff).into()),
- element_background: Some(rgba(0xebeae3ff).into()),
- element_hover: Some(rgba(0xd1d0c6ff).into()),
- element_active: Some(rgba(0x989788ff).into()),
- element_selected: Some(rgba(0x989788ff).into()),
- element_disabled: Some(rgba(0xebeae3ff).into()),
- drop_target_background: Some(rgba(0x61604f80).into()),
+ border_disabled: Some(rgba(0x48434fff).into()),
+ elevated_surface_background: Some(rgba(0x221f26ff).into()),
+ surface_background: Some(rgba(0x221f26ff).into()),
+ background: Some(rgba(0x3a353fff).into()),
+ panel_background: Some(rgba(0x221f26ff).into()),
+ element_background: Some(rgba(0x221f26ff).into()),
+ element_hover: Some(rgba(0x332f38ff).into()),
+ element_active: Some(rgba(0x544f5cff).into()),
+ element_selected: Some(rgba(0x544f5cff).into()),
+ element_disabled: Some(rgba(0x221f26ff).into()),
+ drop_target_background: Some(rgba(0x89859180).into()),
ghost_element_background: Some(rgba(0x00000000).into()),
- ghost_element_hover: Some(rgba(0xd1d0c6ff).into()),
- ghost_element_active: Some(rgba(0x989788ff).into()),
- ghost_element_selected: Some(rgba(0x989788ff).into()),
- ghost_element_disabled: Some(rgba(0xebeae3ff).into()),
- text: Some(rgba(0x22221bff).into()),
- text_muted: Some(rgba(0x61604fff).into()),
- text_placeholder: Some(rgba(0x767463ff).into()),
- text_disabled: Some(rgba(0x767463ff).into()),
- text_accent: Some(rgba(0x38a166ff).into()),
- icon: Some(rgba(0x22221bff).into()),
- icon_muted: Some(rgba(0x61604fff).into()),
- icon_disabled: Some(rgba(0x767463ff).into()),
- icon_placeholder: Some(rgba(0x61604fff).into()),
- icon_accent: Some(rgba(0x38a166ff).into()),
- status_bar_background: Some(rgba(0xc5c4b9ff).into()),
- title_bar_background: Some(rgba(0xc5c4b9ff).into()),
- toolbar_background: Some(rgba(0xf4f3ecff).into()),
- tab_bar_background: Some(rgba(0xebeae3ff).into()),
- tab_inactive_background: Some(rgba(0xebeae3ff).into()),
- tab_active_background: Some(rgba(0xf4f3ecff).into()),
- scrollbar_thumb_background: Some(rgba(0x22221b4c).into()),
- scrollbar_thumb_hover_background: Some(rgba(0xd1d0c6ff).into()),
- scrollbar_thumb_border: Some(rgba(0xd1d0c6ff).into()),
+ ghost_element_hover: Some(rgba(0x332f38ff).into()),
+ ghost_element_active: Some(rgba(0x544f5cff).into()),
+ ghost_element_selected: Some(rgba(0x544f5cff).into()),
+ ghost_element_disabled: Some(rgba(0x221f26ff).into()),
+ text: Some(rgba(0xefecf4ff).into()),
+ text_muted: Some(rgba(0x898591ff).into()),
+ text_placeholder: Some(rgba(0x756f7eff).into()),
+ text_disabled: Some(rgba(0x756f7eff).into()),
+ text_accent: Some(rgba(0x576ddaff).into()),
+ icon: Some(rgba(0xefecf4ff).into()),
+ icon_muted: Some(rgba(0x898591ff).into()),
+ icon_disabled: Some(rgba(0x756f7eff).into()),
+ icon_placeholder: Some(rgba(0x898591ff).into()),
+ icon_accent: Some(rgba(0x576ddaff).into()),
+ status_bar_background: Some(rgba(0x3a353fff).into()),
+ title_bar_background: Some(rgba(0x3a353fff).into()),
+ toolbar_background: Some(rgba(0x19171cff).into()),
+ tab_bar_background: Some(rgba(0x221f26ff).into()),
+ tab_inactive_background: Some(rgba(0x221f26ff).into()),
+ tab_active_background: Some(rgba(0x19171cff).into()),
+ scrollbar_thumb_background: Some(rgba(0xefecf44c).into()),
+ scrollbar_thumb_hover_background: Some(rgba(0x332f38ff).into()),
+ scrollbar_thumb_border: Some(rgba(0x332f38ff).into()),
scrollbar_track_background: Some(rgba(0x00000000).into()),
- scrollbar_track_border: Some(rgba(0xedece5ff).into()),
- editor_foreground: Some(rgba(0x302f27ff).into()),
- editor_background: Some(rgba(0xf4f3ecff).into()),
- editor_gutter_background: Some(rgba(0xf4f3ecff).into()),
- editor_subheader_background: Some(rgba(0xebeae3ff).into()),
- editor_active_line_background: Some(rgba(0xebeae3bf).into()),
- editor_highlighted_line_background: Some(rgba(0xebeae3ff).into()),
- editor_line_number: Some(rgba(0x22221b59).into()),
- editor_active_line_number: Some(rgba(0x22221bff).into()),
- editor_invisible: Some(rgba(0x61604fff).into()),
- editor_wrap_guide: Some(rgba(0x22221b0d).into()),
- editor_active_wrap_guide: Some(rgba(0x22221b1a).into()),
- editor_document_highlight_read_background: Some(rgba(0x38a1661a).into()),
- editor_document_highlight_write_background: Some(rgba(0x7a786766).into()),
- terminal_background: Some(rgba(0xf4f3ecff).into()),
- terminal_ansi_bright_black: Some(rgba(0x898775ff).into()),
- terminal_ansi_bright_red: Some(rgba(0xe4af96ff).into()),
- terminal_ansi_bright_green: Some(rgba(0xc0ca93ff).into()),
- terminal_ansi_bright_yellow: Some(rgba(0xd7ca8dff).into()),
- terminal_ansi_bright_blue: Some(rgba(0xa0d1b0ff).into()),
- terminal_ansi_bright_magenta: Some(rgba(0xcfb4bcff).into()),
- terminal_ansi_bright_cyan: Some(rgba(0xaecea1ff).into()),
- terminal_ansi_bright_white: Some(rgba(0x22221bff).into()),
- terminal_ansi_black: Some(rgba(0xf4f3ecff).into()),
- terminal_ansi_red: Some(rgba(0xba6337ff).into()),
- terminal_ansi_green: Some(rgba(0x7d9728ff).into()),
- terminal_ansi_yellow: Some(rgba(0xa59810ff).into()),
- terminal_ansi_blue: Some(rgba(0x38a166ff).into()),
- terminal_ansi_magenta: Some(rgba(0x9d6c7cff).into()),
- terminal_ansi_cyan: Some(rgba(0x5c9d49ff).into()),
- terminal_ansi_white: Some(rgba(0x22221bff).into()),
- link_text_hover: Some(rgba(0x38a166ff).into()),
+ scrollbar_track_border: Some(rgba(0x201e24ff).into()),
+ editor_foreground: Some(rgba(0xe2dfe7ff).into()),
+ editor_background: Some(rgba(0x19171cff).into()),
+ editor_gutter_background: Some(rgba(0x19171cff).into()),
+ editor_subheader_background: Some(rgba(0x221f26ff).into()),
+ editor_active_line_background: Some(rgba(0x221f26bf).into()),
+ editor_highlighted_line_background: Some(rgba(0x221f26ff).into()),
+ editor_line_number: Some(rgba(0xefecf459).into()),
+ editor_active_line_number: Some(rgba(0xefecf4ff).into()),
+ editor_invisible: Some(rgba(0x898591ff).into()),
+ editor_wrap_guide: Some(rgba(0xefecf40d).into()),
+ editor_active_wrap_guide: Some(rgba(0xefecf41a).into()),
+ editor_document_highlight_read_background: Some(rgba(0x576dda1a).into()),
+ editor_document_highlight_write_background: Some(rgba(0x726c7a66).into()),
+ terminal_background: Some(rgba(0x19171cff).into()),
+ terminal_ansi_bright_black: Some(rgba(0x635d6bff).into()),
+ terminal_ansi_bright_red: Some(rgba(0x5c283cff).into()),
+ terminal_ansi_bright_green: Some(rgba(0x1f4747ff).into()),
+ terminal_ansi_bright_yellow: Some(rgba(0x4e3821ff).into()),
+ terminal_ansi_bright_blue: Some(rgba(0x2d376fff).into()),
+ terminal_ansi_bright_magenta: Some(rgba(0x60255bff).into()),
+ terminal_ansi_bright_cyan: Some(rgba(0x26445eff).into()),
+ terminal_ansi_bright_white: Some(rgba(0xefecf4ff).into()),
+ terminal_ansi_black: Some(rgba(0x19171cff).into()),
+ terminal_ansi_red: Some(rgba(0xbe4678ff).into()),
+ terminal_ansi_green: Some(rgba(0x2c9292ff).into()),
+ terminal_ansi_yellow: Some(rgba(0xa06e3bff).into()),
+ terminal_ansi_blue: Some(rgba(0x576ddaff).into()),
+ terminal_ansi_magenta: Some(rgba(0xbf41bfff).into()),
+ terminal_ansi_cyan: Some(rgba(0x3a8bc6ff).into()),
+ terminal_ansi_white: Some(rgba(0xefecf4ff).into()),
+ link_text_hover: Some(rgba(0x576ddaff).into()),
..Default::default()
},
status: StatusColorsRefinement {
- conflict: Some(rgba(0xa59810ff).into()),
- conflict_background: Some(rgba(0xf0e9d1ff).into()),
- conflict_border: Some(rgba(0xe3d8adff).into()),
- created: Some(rgba(0x7d9728ff).into()),
- created_background: Some(rgba(0xe6e9d3ff).into()),
- created_border: Some(rgba(0xd2d8b1ff).into()),
- deleted: Some(rgba(0xba6337ff).into()),
- deleted_background: Some(rgba(0xf6ded4ff).into()),
- deleted_border: Some(rgba(0xedc5b3ff).into()),
- error: Some(rgba(0xba6337ff).into()),
- error_background: Some(rgba(0xf6ded4ff).into()),
- error_border: Some(rgba(0xedc5b3ff).into()),
- hidden: Some(rgba(0x767463ff).into()),
- hidden_background: Some(rgba(0xc5c4b9ff).into()),
- hidden_border: Some(rgba(0xadac9fff).into()),
- hint: Some(rgba(0x768962ff).into()),
- hint_background: Some(rgba(0xd9ecdfff).into()),
- hint_border: Some(rgba(0xbbddc6ff).into()),
- ignored: Some(rgba(0x61604fff).into()),
- ignored_background: Some(rgba(0xc5c4b9ff).into()),
- ignored_border: Some(rgba(0x969585ff).into()),
- info: Some(rgba(0x38a166ff).into()),
- info_background: Some(rgba(0xd9ecdfff).into()),
- info_border: Some(rgba(0xbbddc6ff).into()),
- modified: Some(rgba(0xa59810ff).into()),
- modified_background: Some(rgba(0xf0e9d1ff).into()),
- modified_border: Some(rgba(0xe3d8adff).into()),
- predictive: Some(rgba(0x879a72ff).into()),
- predictive_background: Some(rgba(0xe6e9d3ff).into()),
- predictive_border: Some(rgba(0xd2d8b1ff).into()),
- renamed: Some(rgba(0x38a166ff).into()),
- renamed_background: Some(rgba(0xd9ecdfff).into()),
- renamed_border: Some(rgba(0xbbddc6ff).into()),
- success: Some(rgba(0x7d9728ff).into()),
- success_background: Some(rgba(0xe6e9d3ff).into()),
- success_border: Some(rgba(0xd2d8b1ff).into()),
- unreachable: Some(rgba(0x61604fff).into()),
- unreachable_background: Some(rgba(0xc5c4b9ff).into()),
- unreachable_border: Some(rgba(0x969585ff).into()),
- warning: Some(rgba(0xa59810ff).into()),
- warning_background: Some(rgba(0xf0e9d1ff).into()),
- warning_border: Some(rgba(0xe3d8adff).into()),
+ conflict: Some(rgba(0xa06e3bff).into()),
+ conflict_background: Some(rgba(0x231a12ff).into()),
+ conflict_border: Some(rgba(0x392a1aff).into()),
+ created: Some(rgba(0x2c9292ff).into()),
+ created_background: Some(rgba(0x132020ff).into()),
+ created_border: Some(rgba(0x1a3434ff).into()),
+ deleted: Some(rgba(0xbe4678ff).into()),
+ deleted_background: Some(rgba(0x28151cff).into()),
+ deleted_border: Some(rgba(0x421f2dff).into()),
+ error: Some(rgba(0xbe4678ff).into()),
+ error_background: Some(rgba(0x28151cff).into()),
+ error_border: Some(rgba(0x421f2dff).into()),
+ hidden: Some(rgba(0x756f7eff).into()),
+ hidden_background: Some(rgba(0x3a353fff).into()),
+ hidden_border: Some(rgba(0x48434fff).into()),
+ hint: Some(rgba(0x716998ff).into()),
+ hint_background: Some(rgba(0x161a36ff).into()),
+ hint_border: Some(rgba(0x222953ff).into()),
+ ignored: Some(rgba(0x898591ff).into()),
+ ignored_background: Some(rgba(0x3a353fff).into()),
+ ignored_border: Some(rgba(0x56505eff).into()),
+ info: Some(rgba(0x576ddaff).into()),
+ info_background: Some(rgba(0x161a36ff).into()),
+ info_border: Some(rgba(0x222953ff).into()),
+ modified: Some(rgba(0xa06e3bff).into()),
+ modified_background: Some(rgba(0x231a12ff).into()),
+ modified_border: Some(rgba(0x392a1aff).into()),
+ predictive: Some(rgba(0x625887ff).into()),
+ predictive_background: Some(rgba(0x132020ff).into()),
+ predictive_border: Some(rgba(0x1a3434ff).into()),
+ renamed: Some(rgba(0x576ddaff).into()),
+ renamed_background: Some(rgba(0x161a36ff).into()),
+ renamed_border: Some(rgba(0x222953ff).into()),
+ success: Some(rgba(0x2c9292ff).into()),
+ success_background: Some(rgba(0x132020ff).into()),
+ success_border: Some(rgba(0x1a3434ff).into()),
+ unreachable: Some(rgba(0x898591ff).into()),
+ unreachable_background: Some(rgba(0x3a353fff).into()),
+ unreachable_border: Some(rgba(0x56505eff).into()),
+ warning: Some(rgba(0xa06e3bff).into()),
+ warning_background: Some(rgba(0x231a12ff).into()),
+ warning_border: Some(rgba(0x392a1aff).into()),
..Default::default()
},
player: Some(PlayerColors(vec![
PlayerColor {
- cursor: rgba(0x38a166ff).into(),
- background: rgba(0x38a166ff).into(),
- selection: rgba(0x38a1663d).into(),
+ cursor: rgba(0x576ddaff).into(),
+ background: rgba(0x576ddaff).into(),
+ selection: rgba(0x576dda3d).into(),
},
PlayerColor {
- cursor: rgba(0x9d6c7cff).into(),
- background: rgba(0x9d6c7cff).into(),
- selection: rgba(0x9d6c7c3d).into(),
+ cursor: rgba(0xbf41bfff).into(),
+ background: rgba(0xbf41bfff).into(),
+ selection: rgba(0xbf41bf3d).into(),
},
PlayerColor {
- cursor: rgba(0xae7315ff).into(),
- background: rgba(0xae7315ff).into(),
- selection: rgba(0xae73153d).into(),
+ cursor: rgba(0xaa573cff).into(),
+ background: rgba(0xaa573cff).into(),
+ selection: rgba(0xaa573c3d).into(),
},
PlayerColor {
- cursor: rgba(0x609182ff).into(),
- background: rgba(0x609182ff).into(),
- selection: rgba(0x6091823d).into(),
+ cursor: rgba(0x955ae6ff).into(),
+ background: rgba(0x955ae6ff).into(),
+ selection: rgba(0x955ae63d).into(),
},
PlayerColor {
- cursor: rgba(0x5c9d49ff).into(),
- background: rgba(0x5c9d49ff).into(),
- selection: rgba(0x5c9d493d).into(),
+ cursor: rgba(0x3a8bc6ff).into(),
+ background: rgba(0x3a8bc6ff).into(),
+ selection: rgba(0x3a8bc63d).into(),
},
PlayerColor {
- cursor: rgba(0xba6337ff).into(),
- background: rgba(0xba6337ff).into(),
- selection: rgba(0xba63373d).into(),
+ cursor: rgba(0xbe4678ff).into(),
+ background: rgba(0xbe4678ff).into(),
+ selection: rgba(0xbe46783d).into(),
},
PlayerColor {
- cursor: rgba(0xa59810ff).into(),
- background: rgba(0xa59810ff).into(),
- selection: rgba(0xa598103d).into(),
+ cursor: rgba(0xa06e3bff).into(),
+ background: rgba(0xa06e3bff).into(),
+ selection: rgba(0xa06e3b3d).into(),
},
PlayerColor {
- cursor: rgba(0x7d9728ff).into(),
- background: rgba(0x7d9728ff).into(),
- selection: rgba(0x7d97283d).into(),
+ cursor: rgba(0x2c9292ff).into(),
+ background: rgba(0x2c9292ff).into(),
+ selection: rgba(0x2c92923d).into(),
},
])),
syntax: Some(UserSyntaxTheme {
@@ -187,63 +187,63 @@ pub fn atelier() -> UserThemeFamily {
(
"attribute".into(),
UserHighlightStyle {
- color: Some(rgba(0x38a166ff).into()),
+ color: Some(rgba(0x576ddaff).into()),
..Default::default()
},
),
(
"boolean".into(),
UserHighlightStyle {
- color: Some(rgba(0x7d9728ff).into()),
+ color: Some(rgba(0x2c9292ff).into()),
..Default::default()
},
),
(
"comment".into(),
UserHighlightStyle {
- color: Some(rgba(0x878573ff).into()),
+ color: Some(rgba(0x655f6dff).into()),
..Default::default()
},
),
(
"comment.doc".into(),
UserHighlightStyle {
- color: Some(rgba(0x5f5e4eff).into()),
+ color: Some(rgba(0x8b8792ff).into()),
..Default::default()
},
),
(
"constant".into(),
UserHighlightStyle {
- color: Some(rgba(0x7d9728ff).into()),
+ color: Some(rgba(0x2c9292ff).into()),
..Default::default()
},
),
(
"constructor".into(),
UserHighlightStyle {
- color: Some(rgba(0x38a166ff).into()),
+ color: Some(rgba(0x576ddaff).into()),
..Default::default()
},
),
(
"embedded".into(),
UserHighlightStyle {
- color: Some(rgba(0x22221bff).into()),
+ color: Some(rgba(0xefecf4ff).into()),
..Default::default()
},
),
(
"emphasis".into(),
UserHighlightStyle {
- color: Some(rgba(0x38a166ff).into()),
+ color: Some(rgba(0x576ddaff).into()),
..Default::default()
},
),
(
"emphasis.strong".into(),
UserHighlightStyle {
- color: Some(rgba(0x38a166ff).into()),
+ color: Some(rgba(0x576ddaff).into()),
font_weight: Some(UserFontWeight(700.0)),
..Default::default()
},
@@ -251,35 +251,35 @@ pub fn atelier() -> UserThemeFamily {
(
"enum".into(),
UserHighlightStyle {
- color: Some(rgba(0xae7315ff).into()),
+ color: Some(rgba(0xaa573cff).into()),
..Default::default()
},
),
(
"function".into(),
UserHighlightStyle {
- color: Some(rgba(0x36a166ff).into()),
+ color: Some(rgba(0x576ddbff).into()),
..Default::default()
},
),
(
"function.method".into(),
UserHighlightStyle {
- color: Some(rgba(0x36a166ff).into()),
+ color: Some(rgba(0x576ddbff).into()),
..Default::default()
},
),
(
"function.special.definition".into(),
UserHighlightStyle {
- color: Some(rgba(0xa5980dff).into()),
+ color: Some(rgba(0xa06e3bff).into()),
..Default::default()
},
),
(
"hint".into(),
UserHighlightStyle {
- color: Some(rgba(0x768962ff).into()),
+ color: Some(rgba(0x716998ff).into()),
font_weight: Some(UserFontWeight(700.0)),
..Default::default()
},
@@ -287,21 +287,21 @@ pub fn atelier() -> UserThemeFamily {
(
"keyword".into(),
UserHighlightStyle {
- color: Some(rgba(0x5f9182ff).into()),
+ color: Some(rgba(0x955ae7ff).into()),
..Default::default()
},
),
(
"label".into(),
UserHighlightStyle {
- color: Some(rgba(0x38a166ff).into()),
+ color: Some(rgba(0x576ddaff).into()),
..Default::default()
},
),
(
"link_text".into(),
UserHighlightStyle {
- color: Some(rgba(0xae7315ff).into()),
+ color: Some(rgba(0xaa573cff).into()),
font_style: Some(UserFontStyle::Italic),
..Default::default()
},
@@ -309,28 +309,28 @@ pub fn atelier() -> UserThemeFamily {
(
"link_uri".into(),
UserHighlightStyle {
- color: Some(rgba(0x7d9728ff).into()),
+ color: Some(rgba(0x2c9292ff).into()),
..Default::default()
},
),
(
"number".into(),
UserHighlightStyle {
- color: Some(rgba(0xae7313ff).into()),
+ color: Some(rgba(0xaa573cff).into()),
..Default::default()
},
),
(
"operator".into(),
UserHighlightStyle {
- color: Some(rgba(0x5f5e4eff).into()),
+ color: Some(rgba(0x8b8792ff).into()),
..Default::default()
},
),
(
"predictive".into(),
UserHighlightStyle {
- color: Some(rgba(0x879a72ff).into()),
+ color: Some(rgba(0x625887ff).into()),
font_style: Some(UserFontStyle::Italic),
..Default::default()
},
@@ -338,112 +338,112 @@ pub fn atelier() -> UserThemeFamily {
(
"preproc".into(),
UserHighlightStyle {
- color: Some(rgba(0x22221bff).into()),
+ color: Some(rgba(0xefecf4ff).into()),
..Default::default()
},
),
(
"primary".into(),
UserHighlightStyle {
- color: Some(rgba(0x302f27ff).into()),
+ color: Some(rgba(0xe2dfe7ff).into()),
..Default::default()
},
),
(
"property".into(),
UserHighlightStyle {
- color: Some(rgba(0xba6236ff).into()),
+ color: Some(rgba(0xbe4678ff).into()),
..Default::default()
},
),
(
"punctuation".into(),
UserHighlightStyle {
- color: Some(rgba(0x302f27ff).into()),
+ color: Some(rgba(0xe2dfe7ff).into()),
..Default::default()
},
),
(
"punctuation.bracket".into(),
UserHighlightStyle {
- color: Some(rgba(0x5f5e4eff).into()),
+ color: Some(rgba(0x8b8792ff).into()),
..Default::default()
},
),
(
"punctuation.delimiter".into(),
UserHighlightStyle {
- color: Some(rgba(0x5f5e4eff).into()),
+ color: Some(rgba(0x8b8792ff).into()),
..Default::default()
},
),
(
"punctuation.list_marker".into(),
UserHighlightStyle {
- color: Some(rgba(0x302f27ff).into()),
+ color: Some(rgba(0xe2dfe7ff).into()),
..Default::default()
},
),
(
"punctuation.special".into(),
UserHighlightStyle {
- color: Some(rgba(0x9d6c7cff).into()),
+ color: Some(rgba(0xbf40bfff).into()),
..Default::default()
},
),
(
"string".into(),
UserHighlightStyle {
- color: Some(rgba(0x7d9726ff).into()),
+ color: Some(rgba(0x2a9292ff).into()),
..Default::default()
},
),
(
"string.escape".into(),
UserHighlightStyle {
- color: Some(rgba(0x5f5e4eff).into()),
+ color: Some(rgba(0x8b8792ff).into()),
..Default::default()
},
),
(
"string.regex".into(),
UserHighlightStyle {
- color: Some(rgba(0x5b9d48ff).into()),
+ color: Some(rgba(0x398bc6ff).into()),
..Default::default()
},
),
(
"string.special".into(),
UserHighlightStyle {
- color: Some(rgba(0x9d6c7cff).into()),
+ color: Some(rgba(0xbf40bfff).into()),
..Default::default()
},
),
(
"string.special.symbol".into(),
UserHighlightStyle {
- color: Some(rgba(0x7d9726ff).into()),
+ color: Some(rgba(0x2a9292ff).into()),
..Default::default()
},
),
(
"tag".into(),
UserHighlightStyle {
- color: Some(rgba(0x38a166ff).into()),
+ color: Some(rgba(0x576ddaff).into()),
..Default::default()
},
),
(
"text.literal".into(),
UserHighlightStyle {
- color: Some(rgba(0xae7315ff).into()),
+ color: Some(rgba(0xaa573cff).into()),
..Default::default()
},
),
(
"title".into(),
UserHighlightStyle {
- color: Some(rgba(0x22221bff).into()),
+ color: Some(rgba(0xefecf4ff).into()),
font_weight: Some(UserFontWeight(700.0)),
..Default::default()
},
@@ -451,28 +451,28 @@ pub fn atelier() -> UserThemeFamily {
(
"type".into(),
UserHighlightStyle {
- color: Some(rgba(0xa5980dff).into()),
+ color: Some(rgba(0xa06e3bff).into()),
..Default::default()
},
),
(
"variable".into(),
UserHighlightStyle {
- color: Some(rgba(0x302f27ff).into()),
+ color: Some(rgba(0xe2dfe7ff).into()),
..Default::default()
},
),
(
"variable.special".into(),
UserHighlightStyle {
- color: Some(rgba(0x5f9182ff).into()),
+ color: Some(rgba(0x955ae7ff).into()),
..Default::default()
},
),
(
"variant".into(),
UserHighlightStyle {
- color: Some(rgba(0xa5980dff).into()),
+ color: Some(rgba(0xa06e3bff).into()),
..Default::default()
},
),
@@ -481,170 +481,170 @@ pub fn atelier() -> UserThemeFamily {
},
},
UserTheme {
- name: "Atelier Forest Dark".into(),
- appearance: Appearance::Dark,
+ name: "Atelier Cave Light".into(),
+ appearance: Appearance::Light,
styles: UserThemeStylesRefinement {
colors: ThemeColorsRefinement {
- border: Some(rgba(0x665f5cff).into()),
- border_variant: Some(rgba(0x3b3431ff).into()),
- border_focused: Some(rgba(0x192e5bff).into()),
- border_selected: Some(rgba(0x192e5bff).into()),
+ border: Some(rgba(0x8f8b96ff).into()),
+ border_variant: Some(rgba(0xcbc8d1ff).into()),
+ border_focused: Some(rgba(0xc9c8f3ff).into()),
+ border_selected: Some(rgba(0xc9c8f3ff).into()),
border_transparent: Some(rgba(0x00000000).into()),
- border_disabled: Some(rgba(0x554e4bff).into()),
- elevated_surface_background: Some(rgba(0x27211eff).into()),
- surface_background: Some(rgba(0x27211eff).into()),
- background: Some(rgba(0x443c39ff).into()),
- panel_background: Some(rgba(0x27211eff).into()),
- element_background: Some(rgba(0x27211eff).into()),
- element_hover: Some(rgba(0x3b3431ff).into()),
- element_active: Some(rgba(0x645d5aff).into()),
- element_selected: Some(rgba(0x645d5aff).into()),
- element_disabled: Some(rgba(0x27211eff).into()),
- drop_target_background: Some(rgba(0xa79f9d80).into()),
+ border_disabled: Some(rgba(0xa7a3adff).into()),
+ elevated_surface_background: Some(rgba(0xe6e3ebff).into()),
+ surface_background: Some(rgba(0xe6e3ebff).into()),
+ background: Some(rgba(0xbfbcc5ff).into()),
+ panel_background: Some(rgba(0xe6e3ebff).into()),
+ element_background: Some(rgba(0xe6e3ebff).into()),
+ element_hover: Some(rgba(0xcbc8d1ff).into()),
+ element_active: Some(rgba(0x918d98ff).into()),
+ element_selected: Some(rgba(0x918d98ff).into()),
+ element_disabled: Some(rgba(0xe6e3ebff).into()),
+ drop_target_background: Some(rgba(0x5a546280).into()),
ghost_element_background: Some(rgba(0x00000000).into()),
- ghost_element_hover: Some(rgba(0x3b3431ff).into()),
- ghost_element_active: Some(rgba(0x645d5aff).into()),
- ghost_element_selected: Some(rgba(0x645d5aff).into()),
- ghost_element_disabled: Some(rgba(0x27211eff).into()),
- text: Some(rgba(0xf1efeeff).into()),
- text_muted: Some(rgba(0xa79f9dff).into()),
- text_placeholder: Some(rgba(0x8e8683ff).into()),
- text_disabled: Some(rgba(0x8e8683ff).into()),
- text_accent: Some(rgba(0x417ee6ff).into()),
- icon: Some(rgba(0xf1efeeff).into()),
- icon_muted: Some(rgba(0xa79f9dff).into()),
- icon_disabled: Some(rgba(0x8e8683ff).into()),
- icon_placeholder: Some(rgba(0xa79f9dff).into()),
- icon_accent: Some(rgba(0x417ee6ff).into()),
- status_bar_background: Some(rgba(0x443c39ff).into()),
- title_bar_background: Some(rgba(0x443c39ff).into()),
- toolbar_background: Some(rgba(0x1b1918ff).into()),
- tab_bar_background: Some(rgba(0x27211eff).into()),
- tab_inactive_background: Some(rgba(0x27211eff).into()),
- tab_active_background: Some(rgba(0x1b1918ff).into()),
- scrollbar_thumb_background: Some(rgba(0xf1efee4c).into()),
- scrollbar_thumb_hover_background: Some(rgba(0x3b3431ff).into()),
- scrollbar_thumb_border: Some(rgba(0x3b3431ff).into()),
+ ghost_element_hover: Some(rgba(0xcbc8d1ff).into()),
+ ghost_element_active: Some(rgba(0x918d98ff).into()),
+ ghost_element_selected: Some(rgba(0x918d98ff).into()),
+ ghost_element_disabled: Some(rgba(0xe6e3ebff).into()),
+ text: Some(rgba(0x19171cff).into()),
+ text_muted: Some(rgba(0x5a5462ff).into()),
+ text_placeholder: Some(rgba(0x6e6876ff).into()),
+ text_disabled: Some(rgba(0x6e6876ff).into()),
+ text_accent: Some(rgba(0x586ddaff).into()),
+ icon: Some(rgba(0x19171cff).into()),
+ icon_muted: Some(rgba(0x5a5462ff).into()),
+ icon_disabled: Some(rgba(0x6e6876ff).into()),
+ icon_placeholder: Some(rgba(0x5a5462ff).into()),
+ icon_accent: Some(rgba(0x586ddaff).into()),
+ status_bar_background: Some(rgba(0xbfbcc5ff).into()),
+ title_bar_background: Some(rgba(0xbfbcc5ff).into()),
+ toolbar_background: Some(rgba(0xefecf4ff).into()),
+ tab_bar_background: Some(rgba(0xe6e3ebff).into()),
+ tab_inactive_background: Some(rgba(0xe6e3ebff).into()),
+ tab_active_background: Some(rgba(0xefecf4ff).into()),
+ scrollbar_thumb_background: Some(rgba(0x19171c4c).into()),
+ scrollbar_thumb_hover_background: Some(rgba(0xcbc8d1ff).into()),
+ scrollbar_thumb_border: Some(rgba(0xcbc8d1ff).into()),
scrollbar_track_background: Some(rgba(0x00000000).into()),
- scrollbar_track_border: Some(rgba(0x251f1dff).into()),
- editor_foreground: Some(rgba(0xe6e2e0ff).into()),
- editor_background: Some(rgba(0x1b1918ff).into()),
- editor_gutter_background: Some(rgba(0x1b1918ff).into()),
- editor_subheader_background: Some(rgba(0x27211eff).into()),
- editor_active_line_background: Some(rgba(0x27211ebf).into()),
- editor_highlighted_line_background: Some(rgba(0x27211eff).into()),
- editor_line_number: Some(rgba(0xf1efee59).into()),
- editor_active_line_number: Some(rgba(0xf1efeeff).into()),
- editor_invisible: Some(rgba(0xa79f9dff).into()),
- editor_wrap_guide: Some(rgba(0xf1efee0d).into()),
- editor_active_wrap_guide: Some(rgba(0xf1efee1a).into()),
- editor_document_highlight_read_background: Some(rgba(0x417ee61a).into()),
- editor_document_highlight_write_background: Some(rgba(0x89817e66).into()),
- terminal_background: Some(rgba(0x1b1918ff).into()),
- terminal_ansi_bright_black: Some(rgba(0x746c69ff).into()),
- terminal_ansi_bright_red: Some(rgba(0x8c1223ff).into()),
- terminal_ansi_bright_green: Some(rgba(0x3e491aff).into()),
- terminal_ansi_bright_yellow: Some(rgba(0x674115ff).into()),
- terminal_ansi_bright_blue: Some(rgba(0x213f78ff).into()),
- terminal_ansi_bright_magenta: Some(rgba(0x662186ff).into()),
- terminal_ansi_bright_cyan: Some(rgba(0x264958ff).into()),
- terminal_ansi_bright_white: Some(rgba(0xf1efeeff).into()),
- terminal_ansi_black: Some(rgba(0x1b1918ff).into()),
- terminal_ansi_red: Some(rgba(0xf22d40ff).into()),
- terminal_ansi_green: Some(rgba(0x7b9727ff).into()),
- terminal_ansi_yellow: Some(rgba(0xc38419ff).into()),
- terminal_ansi_blue: Some(rgba(0x417ee6ff).into()),
- terminal_ansi_magenta: Some(rgba(0xc340f2ff).into()),
- terminal_ansi_cyan: Some(rgba(0x3e97b8ff).into()),
- terminal_ansi_white: Some(rgba(0xf1efeeff).into()),
- link_text_hover: Some(rgba(0x417ee6ff).into()),
+ scrollbar_track_border: Some(rgba(0xe8e5edff).into()),
+ editor_foreground: Some(rgba(0x26232aff).into()),
+ editor_background: Some(rgba(0xefecf4ff).into()),
+ editor_gutter_background: Some(rgba(0xefecf4ff).into()),
+ editor_subheader_background: Some(rgba(0xe6e3ebff).into()),
+ editor_active_line_background: Some(rgba(0xe6e3ebbf).into()),
+ editor_highlighted_line_background: Some(rgba(0xe6e3ebff).into()),
+ editor_line_number: Some(rgba(0x19171c59).into()),
+ editor_active_line_number: Some(rgba(0x19171cff).into()),
+ editor_invisible: Some(rgba(0x5a5462ff).into()),
+ editor_wrap_guide: Some(rgba(0x19171c0d).into()),
+ editor_active_wrap_guide: Some(rgba(0x19171c1a).into()),
+ editor_document_highlight_read_background: Some(rgba(0x586dda1a).into()),
+ editor_document_highlight_write_background: Some(rgba(0x726c7a66).into()),
+ terminal_background: Some(rgba(0xefecf4ff).into()),
+ terminal_ansi_bright_black: Some(rgba(0x807b89ff).into()),
+ terminal_ansi_bright_red: Some(rgba(0xe3a4b9ff).into()),
+ terminal_ansi_bright_green: Some(rgba(0x9dc8c8ff).into()),
+ terminal_ansi_bright_yellow: Some(rgba(0xd4b499ff).into()),
+ terminal_ansi_bright_blue: Some(rgba(0xb3b3eeff).into()),
+ terminal_ansi_bright_magenta: Some(rgba(0xe3a4dfff).into()),
+ terminal_ansi_bright_cyan: Some(rgba(0xa6c4e3ff).into()),
+ terminal_ansi_bright_white: Some(rgba(0x19171cff).into()),
+ terminal_ansi_black: Some(rgba(0xefecf4ff).into()),
+ terminal_ansi_red: Some(rgba(0xbe4778ff).into()),
+ terminal_ansi_green: Some(rgba(0x2c9292ff).into()),
+ terminal_ansi_yellow: Some(rgba(0xa06e3cff).into()),
+ terminal_ansi_blue: Some(rgba(0x586ddaff).into()),
+ terminal_ansi_magenta: Some(rgba(0xbf41bfff).into()),
+ terminal_ansi_cyan: Some(rgba(0x3b8bc6ff).into()),
+ terminal_ansi_white: Some(rgba(0x19171cff).into()),
+ link_text_hover: Some(rgba(0x586ddaff).into()),
..Default::default()
},
status: StatusColorsRefinement {
- conflict: Some(rgba(0xc38419ff).into()),
- conflict_background: Some(rgba(0x371d0dff).into()),
- conflict_border: Some(rgba(0x4f2f12ff).into()),
- created: Some(rgba(0x7b9727ff).into()),
- created_background: Some(rgba(0x1d2110ff).into()),
- created_border: Some(rgba(0x2e3516ff).into()),
- deleted: Some(rgba(0xf22d40ff).into()),
- deleted_background: Some(rgba(0x550512ff).into()),
- deleted_border: Some(rgba(0x710c1bff).into()),
- error: Some(rgba(0xf22d40ff).into()),
- error_background: Some(rgba(0x550512ff).into()),
- error_border: Some(rgba(0x710c1bff).into()),
- hidden: Some(rgba(0x8e8683ff).into()),
- hidden_background: Some(rgba(0x443c39ff).into()),
- hidden_border: Some(rgba(0x554e4bff).into()),
- hint: Some(rgba(0xa87187ff).into()),
- hint_background: Some(rgba(0x0f1d3dff).into()),
- hint_border: Some(rgba(0x192e5bff).into()),
- ignored: Some(rgba(0xa79f9dff).into()),
- ignored_background: Some(rgba(0x443c39ff).into()),
- ignored_border: Some(rgba(0x665f5cff).into()),
- info: Some(rgba(0x417ee6ff).into()),
- info_background: Some(rgba(0x0f1d3dff).into()),
- info_border: Some(rgba(0x192e5bff).into()),
- modified: Some(rgba(0xc38419ff).into()),
- modified_background: Some(rgba(0x371d0dff).into()),
- modified_border: Some(rgba(0x4f2f12ff).into()),
- predictive: Some(rgba(0x8f5b71ff).into()),
- predictive_background: Some(rgba(0x1d2110ff).into()),
- predictive_border: Some(rgba(0x2e3516ff).into()),
- renamed: Some(rgba(0x417ee6ff).into()),
- renamed_background: Some(rgba(0x0f1d3dff).into()),
- renamed_border: Some(rgba(0x192e5bff).into()),
- success: Some(rgba(0x7b9727ff).into()),
- success_background: Some(rgba(0x1d2110ff).into()),
- success_border: Some(rgba(0x2e3516ff).into()),
- unreachable: Some(rgba(0xa79f9dff).into()),
- unreachable_background: Some(rgba(0x443c39ff).into()),
- unreachable_border: Some(rgba(0x665f5cff).into()),
- warning: Some(rgba(0xc38419ff).into()),
- warning_background: Some(rgba(0x371d0dff).into()),
- warning_border: Some(rgba(0x4f2f12ff).into()),
+ conflict: Some(rgba(0xa06e3cff).into()),
+ conflict_background: Some(rgba(0xeee0d5ff).into()),
+ conflict_border: Some(rgba(0xe0c9b5ff).into()),
+ created: Some(rgba(0x2c9292ff).into()),
+ created_background: Some(rgba(0xd7e9e8ff).into()),
+ created_border: Some(rgba(0xb9d7d6ff).into()),
+ deleted: Some(rgba(0xbe4778ff).into()),
+ deleted_background: Some(rgba(0xf5dae2ff).into()),
+ deleted_border: Some(rgba(0xecbecdff).into()),
+ error: Some(rgba(0xbe4778ff).into()),
+ error_background: Some(rgba(0xf5dae2ff).into()),
+ error_border: Some(rgba(0xecbecdff).into()),
+ hidden: Some(rgba(0x6e6876ff).into()),
+ hidden_background: Some(rgba(0xbfbcc5ff).into()),
+ hidden_border: Some(rgba(0xa7a3adff).into()),
+ hint: Some(rgba(0x786e9dff).into()),
+ hint_background: Some(rgba(0xe1e0f9ff).into()),
+ hint_border: Some(rgba(0xc9c8f3ff).into()),
+ ignored: Some(rgba(0x5a5462ff).into()),
+ ignored_background: Some(rgba(0xbfbcc5ff).into()),
+ ignored_border: Some(rgba(0x8f8b96ff).into()),
+ info: Some(rgba(0x586ddaff).into()),
+ info_background: Some(rgba(0xe1e0f9ff).into()),
+ info_border: Some(rgba(0xc9c8f3ff).into()),
+ modified: Some(rgba(0xa06e3cff).into()),
+ modified_background: Some(rgba(0xeee0d5ff).into()),
+ modified_border: Some(rgba(0xe0c9b5ff).into()),
+ predictive: Some(rgba(0x887fafff).into()),
+ predictive_background: Some(rgba(0xd7e9e8ff).into()),
+ predictive_border: Some(rgba(0xb9d7d6ff).into()),
+ renamed: Some(rgba(0x586ddaff).into()),
+ renamed_background: Some(rgba(0xe1e0f9ff).into()),
+ renamed_border: Some(rgba(0xc9c8f3ff).into()),
+ success: Some(rgba(0x2c9292ff).into()),
+ success_background: Some(rgba(0xd7e9e8ff).into()),
+ success_border: Some(rgba(0xb9d7d6ff).into()),
+ unreachable: Some(rgba(0x5a5462ff).into()),
+ unreachable_background: Some(rgba(0xbfbcc5ff).into()),
+ unreachable_border: Some(rgba(0x8f8b96ff).into()),
+ warning: Some(rgba(0xa06e3cff).into()),
+ warning_background: Some(rgba(0xeee0d5ff).into()),
+ warning_border: Some(rgba(0xe0c9b5ff).into()),
..Default::default()
},
player: Some(PlayerColors(vec![
PlayerColor {
- cursor: rgba(0x417ee6ff).into(),
- background: rgba(0x417ee6ff).into(),
- selection: rgba(0x417ee63d).into(),
+ cursor: rgba(0x586ddaff).into(),
+ background: rgba(0x586ddaff).into(),
+ selection: rgba(0x586dda3d).into(),
},
PlayerColor {
- cursor: rgba(0xc340f2ff).into(),
- background: rgba(0xc340f2ff).into(),
- selection: rgba(0xc340f23d).into(),
+ cursor: rgba(0xbf41bfff).into(),
+ background: rgba(0xbf41bfff).into(),
+ selection: rgba(0xbf41bf3d).into(),
},
PlayerColor {
- cursor: rgba(0xdf5321ff).into(),
- background: rgba(0xdf5321ff).into(),
- selection: rgba(0xdf53213d).into(),
+ cursor: rgba(0xaa583dff).into(),
+ background: rgba(0xaa583dff).into(),
+ selection: rgba(0xaa583d3d).into(),
},
PlayerColor {
- cursor: rgba(0x6666e9ff).into(),
- background: rgba(0x6666e9ff).into(),
- selection: rgba(0x6666e93d).into(),
+ cursor: rgba(0x955be6ff).into(),
+ background: rgba(0x955be6ff).into(),
+ selection: rgba(0x955be63d).into(),
},
PlayerColor {
- cursor: rgba(0x3e97b8ff).into(),
- background: rgba(0x3e97b8ff).into(),
- selection: rgba(0x3e97b83d).into(),
+ cursor: rgba(0x3b8bc6ff).into(),
+ background: rgba(0x3b8bc6ff).into(),
+ selection: rgba(0x3b8bc63d).into(),
},
PlayerColor {
- cursor: rgba(0xf22d40ff).into(),
- background: rgba(0xf22d40ff).into(),
- selection: rgba(0xf22d403d).into(),
+ cursor: rgba(0xbe4778ff).into(),
+ background: rgba(0xbe4778ff).into(),
+ selection: rgba(0xbe47783d).into(),
},
PlayerColor {
- cursor: rgba(0xc38419ff).into(),
- background: rgba(0xc38419ff).into(),
- selection: rgba(0xc384193d).into(),
+ cursor: rgba(0xa06e3cff).into(),
+ background: rgba(0xa06e3cff).into(),
+ selection: rgba(0xa06e3c3d).into(),
},
PlayerColor {
- cursor: rgba(0x7b9727ff).into(),
- background: rgba(0x7b9727ff).into(),
- selection: rgba(0x7b97273d).into(),
+ cursor: rgba(0x2c9292ff).into(),
+ background: rgba(0x2c9292ff).into(),
+ selection: rgba(0x2c92923d).into(),
},
])),
syntax: Some(UserSyntaxTheme {
@@ -652,63 +652,63 @@ pub fn atelier() -> UserThemeFamily {
(
"attribute".into(),
UserHighlightStyle {
- color: Some(rgba(0x417ee6ff).into()),
+ color: Some(rgba(0x586ddaff).into()),
..Default::default()
},
),
(
"boolean".into(),
UserHighlightStyle {
- color: Some(rgba(0x7b9727ff).into()),
+ color: Some(rgba(0x2c9292ff).into()),
..Default::default()
},
),
(
"comment".into(),
UserHighlightStyle {
- color: Some(rgba(0x766e6bff).into()),
+ color: Some(rgba(0x7e7887ff).into()),
..Default::default()
},
),
(
"comment.doc".into(),
UserHighlightStyle {
- color: Some(rgba(0xa8a19fff).into()),
+ color: Some(rgba(0x585260ff).into()),
..Default::default()
},
),
(
"constant".into(),
UserHighlightStyle {
- color: Some(rgba(0x7b9727ff).into()),
+ color: Some(rgba(0x2c9292ff).into()),
..Default::default()
},
),
(
"constructor".into(),
UserHighlightStyle {
- color: Some(rgba(0x417ee6ff).into()),
+ color: Some(rgba(0x586ddaff).into()),
..Default::default()
},
),
(
"embedded".into(),
UserHighlightStyle {
- color: Some(rgba(0xf1efeeff).into()),
+ color: Some(rgba(0x19171cff).into()),
..Default::default()
},
),
(
"emphasis".into(),
UserHighlightStyle {
- color: Some(rgba(0x417ee6ff).into()),
+ color: Some(rgba(0x586ddaff).into()),
..Default::default()
},
),
(
"emphasis.strong".into(),
UserHighlightStyle {
- color: Some(rgba(0x417ee6ff).into()),
+ color: Some(rgba(0x586ddaff).into()),
font_weight: Some(UserFontWeight(700.0)),
..Default::default()
},
@@ -16,170 +16,170 @@ pub fn gruvbox() -> UserThemeFamily {
author: "Zed Industries".into(),
themes: vec![
UserTheme {
- name: "Gruvbox Light Hard".into(),
- appearance: Appearance::Light,
+ name: "Gruvbox Dark".into(),
+ appearance: Appearance::Dark,
styles: UserThemeStylesRefinement {
colors: ThemeColorsRefinement {
- border: Some(rgba(0xc9b99aff).into()),
- border_variant: Some(rgba(0xddcca7ff).into()),
- border_focused: Some(rgba(0xaec6cdff).into()),
- border_selected: Some(rgba(0xaec6cdff).into()),
+ border: Some(rgba(0x5b534dff).into()),
+ border_variant: Some(rgba(0x494340ff).into()),
+ border_focused: Some(rgba(0x303a36ff).into()),
+ border_selected: Some(rgba(0x303a36ff).into()),
border_transparent: Some(rgba(0x00000000).into()),
- border_disabled: Some(rgba(0xd1c09eff).into()),
- elevated_surface_background: Some(rgba(0xecddb5ff).into()),
- surface_background: Some(rgba(0xecddb5ff).into()),
- background: Some(rgba(0xd9c8a4ff).into()),
- panel_background: Some(rgba(0xecddb5ff).into()),
- element_background: Some(rgba(0xecddb5ff).into()),
- element_hover: Some(rgba(0xddcca7ff).into()),
- element_active: Some(rgba(0xc9b99aff).into()),
- element_selected: Some(rgba(0xc9b99aff).into()),
- element_disabled: Some(rgba(0xecddb5ff).into()),
- drop_target_background: Some(rgba(0x5f565080).into()),
+ border_disabled: Some(rgba(0x544c48ff).into()),
+ elevated_surface_background: Some(rgba(0x3a3735ff).into()),
+ surface_background: Some(rgba(0x3a3735ff).into()),
+ background: Some(rgba(0x4c4642ff).into()),
+ panel_background: Some(rgba(0x3a3735ff).into()),
+ element_background: Some(rgba(0x3a3735ff).into()),
+ element_hover: Some(rgba(0x494340ff).into()),
+ element_active: Some(rgba(0x5b524cff).into()),
+ element_selected: Some(rgba(0x5b524cff).into()),
+ element_disabled: Some(rgba(0x3a3735ff).into()),
+ drop_target_background: Some(rgba(0xc5b59780).into()),
ghost_element_background: Some(rgba(0x00000000).into()),
- ghost_element_hover: Some(rgba(0xddcca7ff).into()),
- ghost_element_active: Some(rgba(0xc9b99aff).into()),
- ghost_element_selected: Some(rgba(0xc9b99aff).into()),
- ghost_element_disabled: Some(rgba(0xecddb5ff).into()),
- text: Some(rgba(0x282828ff).into()),
- text_muted: Some(rgba(0x5f5650ff).into()),
- text_placeholder: Some(rgba(0x8a7c6fff).into()),
- text_disabled: Some(rgba(0x8a7c6fff).into()),
- text_accent: Some(rgba(0x0b6678ff).into()),
- icon: Some(rgba(0x282828ff).into()),
- icon_muted: Some(rgba(0x5f5650ff).into()),
- icon_disabled: Some(rgba(0x8a7c6fff).into()),
- icon_placeholder: Some(rgba(0x5f5650ff).into()),
- icon_accent: Some(rgba(0x0b6678ff).into()),
- status_bar_background: Some(rgba(0xd9c8a4ff).into()),
- title_bar_background: Some(rgba(0xd9c8a4ff).into()),
- toolbar_background: Some(rgba(0xf9f5d7ff).into()),
- tab_bar_background: Some(rgba(0xecddb5ff).into()),
- tab_inactive_background: Some(rgba(0xecddb5ff).into()),
- tab_active_background: Some(rgba(0xf9f5d7ff).into()),
- scrollbar_thumb_background: Some(rgba(0x2828284c).into()),
- scrollbar_thumb_hover_background: Some(rgba(0xddcca7ff).into()),
- scrollbar_thumb_border: Some(rgba(0xddcca7ff).into()),
+ ghost_element_hover: Some(rgba(0x494340ff).into()),
+ ghost_element_active: Some(rgba(0x5b524cff).into()),
+ ghost_element_selected: Some(rgba(0x5b524cff).into()),
+ ghost_element_disabled: Some(rgba(0x3a3735ff).into()),
+ text: Some(rgba(0xfbf1c7ff).into()),
+ text_muted: Some(rgba(0xc5b597ff).into()),
+ text_placeholder: Some(rgba(0x9a8c79ff).into()),
+ text_disabled: Some(rgba(0x9a8c79ff).into()),
+ text_accent: Some(rgba(0x83a598ff).into()),
+ icon: Some(rgba(0xfbf1c7ff).into()),
+ icon_muted: Some(rgba(0xc5b597ff).into()),
+ icon_disabled: Some(rgba(0x9a8c79ff).into()),
+ icon_placeholder: Some(rgba(0xc5b597ff).into()),
+ icon_accent: Some(rgba(0x83a598ff).into()),
+ status_bar_background: Some(rgba(0x4c4642ff).into()),
+ title_bar_background: Some(rgba(0x4c4642ff).into()),
+ toolbar_background: Some(rgba(0x282828ff).into()),
+ tab_bar_background: Some(rgba(0x3a3735ff).into()),
+ tab_inactive_background: Some(rgba(0x3a3735ff).into()),
+ tab_active_background: Some(rgba(0x282828ff).into()),
+ scrollbar_thumb_background: Some(rgba(0xfbf1c74c).into()),
+ scrollbar_thumb_hover_background: Some(rgba(0x494340ff).into()),
+ scrollbar_thumb_border: Some(rgba(0x494340ff).into()),
scrollbar_track_background: Some(rgba(0x00000000).into()),
- scrollbar_track_border: Some(rgba(0xefe2bcff).into()),
- editor_foreground: Some(rgba(0x282828ff).into()),
- editor_background: Some(rgba(0xf9f5d7ff).into()),
- editor_gutter_background: Some(rgba(0xf9f5d7ff).into()),
- editor_subheader_background: Some(rgba(0xecddb5ff).into()),
- editor_active_line_background: Some(rgba(0xecddb5bf).into()),
- editor_highlighted_line_background: Some(rgba(0xecddb5ff).into()),
- editor_line_number: Some(rgba(0x28282859).into()),
- editor_active_line_number: Some(rgba(0x282828ff).into()),
- editor_invisible: Some(rgba(0x5f5650ff).into()),
- editor_wrap_guide: Some(rgba(0x2828280d).into()),
- editor_active_wrap_guide: Some(rgba(0x2828281a).into()),
- editor_document_highlight_read_background: Some(rgba(0x0b66781a).into()),
+ scrollbar_track_border: Some(rgba(0x373432ff).into()),
+ editor_foreground: Some(rgba(0xebdbb2ff).into()),
+ editor_background: Some(rgba(0x282828ff).into()),
+ editor_gutter_background: Some(rgba(0x282828ff).into()),
+ editor_subheader_background: Some(rgba(0x3a3735ff).into()),
+ editor_active_line_background: Some(rgba(0x3a3735bf).into()),
+ editor_highlighted_line_background: Some(rgba(0x3a3735ff).into()),
+ editor_line_number: Some(rgba(0xfbf1c759).into()),
+ editor_active_line_number: Some(rgba(0xfbf1c7ff).into()),
+ editor_invisible: Some(rgba(0xc5b597ff).into()),
+ editor_wrap_guide: Some(rgba(0xfbf1c70d).into()),
+ editor_active_wrap_guide: Some(rgba(0xfbf1c71a).into()),
+ editor_document_highlight_read_background: Some(rgba(0x83a5981a).into()),
editor_document_highlight_write_background: Some(rgba(0x92847466).into()),
- terminal_background: Some(rgba(0xf9f5d7ff).into()),
- terminal_ansi_bright_black: Some(rgba(0xb1a28aff).into()),
- terminal_ansi_bright_red: Some(rgba(0xdc8c7bff).into()),
- terminal_ansi_bright_green: Some(rgba(0xbfb787ff).into()),
- terminal_ansi_bright_yellow: Some(rgba(0xe2b88bff).into()),
- terminal_ansi_bright_blue: Some(rgba(0x8fb0baff).into()),
- terminal_ansi_bright_magenta: Some(rgba(0xbcb5afff).into()),
- terminal_ansi_bright_cyan: Some(rgba(0x9fbca8ff).into()),
- terminal_ansi_bright_white: Some(rgba(0x282828ff).into()),
- terminal_ansi_black: Some(rgba(0xf9f5d7ff).into()),
- terminal_ansi_red: Some(rgba(0x9d0408ff).into()),
- terminal_ansi_green: Some(rgba(0x797410ff).into()),
- terminal_ansi_yellow: Some(rgba(0xb57616ff).into()),
- terminal_ansi_blue: Some(rgba(0x0b6678ff).into()),
- terminal_ansi_magenta: Some(rgba(0x7c6f64ff).into()),
- terminal_ansi_cyan: Some(rgba(0x437b59ff).into()),
- terminal_ansi_white: Some(rgba(0x282828ff).into()),
- link_text_hover: Some(rgba(0x0b6678ff).into()),
+ terminal_background: Some(rgba(0x282828ff).into()),
+ terminal_ansi_bright_black: Some(rgba(0x73675eff).into()),
+ terminal_ansi_bright_red: Some(rgba(0x93211eff).into()),
+ terminal_ansi_bright_green: Some(rgba(0x615d1bff).into()),
+ terminal_ansi_bright_yellow: Some(rgba(0x91611cff).into()),
+ terminal_ansi_bright_blue: Some(rgba(0x414f4aff).into()),
+ terminal_ansi_bright_magenta: Some(rgba(0x514a41ff).into()),
+ terminal_ansi_bright_cyan: Some(rgba(0x45603eff).into()),
+ terminal_ansi_bright_white: Some(rgba(0xfbf1c7ff).into()),
+ terminal_ansi_black: Some(rgba(0x282828ff).into()),
+ terminal_ansi_red: Some(rgba(0xfb4a35ff).into()),
+ terminal_ansi_green: Some(rgba(0xb8bb27ff).into()),
+ terminal_ansi_yellow: Some(rgba(0xf9bd30ff).into()),
+ terminal_ansi_blue: Some(rgba(0x83a598ff).into()),
+ terminal_ansi_magenta: Some(rgba(0xa89984ff).into()),
+ terminal_ansi_cyan: Some(rgba(0x8ec07cff).into()),
+ terminal_ansi_white: Some(rgba(0xfbf1c7ff).into()),
+ link_text_hover: Some(rgba(0x83a598ff).into()),
..Default::default()
},
status: StatusColorsRefinement {
- conflict: Some(rgba(0xb57616ff).into()),
- conflict_background: Some(rgba(0xf5e2d0ff).into()),
- conflict_border: Some(rgba(0xebccabff).into()),
- created: Some(rgba(0x797410ff).into()),
- created_background: Some(rgba(0xe5e1ceff).into()),
- created_border: Some(rgba(0xd1cba8ff).into()),
- deleted: Some(rgba(0x9d0408ff).into()),
- deleted_background: Some(rgba(0xf4d1c9ff).into()),
- deleted_border: Some(rgba(0xe8ac9eff).into()),
- error: Some(rgba(0x9d0408ff).into()),
- error_background: Some(rgba(0xf4d1c9ff).into()),
- error_border: Some(rgba(0xe8ac9eff).into()),
- hidden: Some(rgba(0x8a7c6fff).into()),
- hidden_background: Some(rgba(0xd9c8a4ff).into()),
- hidden_border: Some(rgba(0xd1c09eff).into()),
- hint: Some(rgba(0x677562ff).into()),
- hint_background: Some(rgba(0xd2dee2ff).into()),
- hint_border: Some(rgba(0xaec6cdff).into()),
- ignored: Some(rgba(0x5f5650ff).into()),
- ignored_background: Some(rgba(0xd9c8a4ff).into()),
- ignored_border: Some(rgba(0xc9b99aff).into()),
- info: Some(rgba(0x0b6678ff).into()),
- info_background: Some(rgba(0xd2dee2ff).into()),
- info_border: Some(rgba(0xaec6cdff).into()),
- modified: Some(rgba(0xb57616ff).into()),
- modified_background: Some(rgba(0xf5e2d0ff).into()),
- modified_border: Some(rgba(0xebccabff).into()),
- predictive: Some(rgba(0x7d9881ff).into()),
- predictive_background: Some(rgba(0xe5e1ceff).into()),
- predictive_border: Some(rgba(0xd1cba8ff).into()),
- renamed: Some(rgba(0x0b6678ff).into()),
- renamed_background: Some(rgba(0xd2dee2ff).into()),
- renamed_border: Some(rgba(0xaec6cdff).into()),
- success: Some(rgba(0x797410ff).into()),
- success_background: Some(rgba(0xe5e1ceff).into()),
- success_border: Some(rgba(0xd1cba8ff).into()),
- unreachable: Some(rgba(0x5f5650ff).into()),
- unreachable_background: Some(rgba(0xd9c8a4ff).into()),
- unreachable_border: Some(rgba(0xc9b99aff).into()),
- warning: Some(rgba(0xb57616ff).into()),
- warning_background: Some(rgba(0xf5e2d0ff).into()),
- warning_border: Some(rgba(0xebccabff).into()),
+ conflict: Some(rgba(0xf9bd30ff).into()),
+ conflict_background: Some(rgba(0x582f10ff).into()),
+ conflict_border: Some(rgba(0x754916ff).into()),
+ created: Some(rgba(0xb8bb27ff).into()),
+ created_background: Some(rgba(0x332b11ff).into()),
+ created_border: Some(rgba(0x4a4516ff).into()),
+ deleted: Some(rgba(0xfb4a35ff).into()),
+ deleted_background: Some(rgba(0x5a0a10ff).into()),
+ deleted_border: Some(rgba(0x771618ff).into()),
+ error: Some(rgba(0xfb4a35ff).into()),
+ error_background: Some(rgba(0x5a0a10ff).into()),
+ error_border: Some(rgba(0x771618ff).into()),
+ hidden: Some(rgba(0x9a8c79ff).into()),
+ hidden_background: Some(rgba(0x4c4642ff).into()),
+ hidden_border: Some(rgba(0x544c48ff).into()),
+ hint: Some(rgba(0x8d957eff).into()),
+ hint_background: Some(rgba(0x1e2321ff).into()),
+ hint_border: Some(rgba(0x303a36ff).into()),
+ ignored: Some(rgba(0xc5b597ff).into()),
+ ignored_background: Some(rgba(0x4c4642ff).into()),
+ ignored_border: Some(rgba(0x5b534dff).into()),
+ info: Some(rgba(0x83a598ff).into()),
+ info_background: Some(rgba(0x1e2321ff).into()),
+ info_border: Some(rgba(0x303a36ff).into()),
+ modified: Some(rgba(0xf9bd30ff).into()),
+ modified_background: Some(rgba(0x582f10ff).into()),
+ modified_border: Some(rgba(0x754916ff).into()),
+ predictive: Some(rgba(0x717363ff).into()),
+ predictive_background: Some(rgba(0x332b11ff).into()),
+ predictive_border: Some(rgba(0x4a4516ff).into()),
+ renamed: Some(rgba(0x83a598ff).into()),
+ renamed_background: Some(rgba(0x1e2321ff).into()),
+ renamed_border: Some(rgba(0x303a36ff).into()),
+ success: Some(rgba(0xb8bb27ff).into()),
+ success_background: Some(rgba(0x332b11ff).into()),
+ success_border: Some(rgba(0x4a4516ff).into()),
+ unreachable: Some(rgba(0xc5b597ff).into()),
+ unreachable_background: Some(rgba(0x4c4642ff).into()),
+ unreachable_border: Some(rgba(0x5b534dff).into()),
+ warning: Some(rgba(0xf9bd30ff).into()),
+ warning_background: Some(rgba(0x582f10ff).into()),
+ warning_border: Some(rgba(0x754916ff).into()),
..Default::default()
},
player: Some(PlayerColors(vec![
PlayerColor {
- cursor: rgba(0x0b6678ff).into(),
- background: rgba(0x0b6678ff).into(),
- selection: rgba(0x0b66783d).into(),
+ cursor: rgba(0x83a598ff).into(),
+ background: rgba(0x83a598ff).into(),
+ selection: rgba(0x83a5983d).into(),
},
PlayerColor {
- cursor: rgba(0x7c6f64ff).into(),
- background: rgba(0x7c6f64ff).into(),
- selection: rgba(0x7c6f643d).into(),
+ cursor: rgba(0xa89984ff).into(),
+ background: rgba(0xa89984ff).into(),
+ selection: rgba(0xa899843d).into(),
},
PlayerColor {
- cursor: rgba(0xaf3b05ff).into(),
- background: rgba(0xaf3b05ff).into(),
- selection: rgba(0xaf3b053d).into(),
+ cursor: rgba(0xfd801bff).into(),
+ background: rgba(0xfd801bff).into(),
+ selection: rgba(0xfd801b3d).into(),
},
PlayerColor {
- cursor: rgba(0x8f4071ff).into(),
- background: rgba(0x8f4071ff).into(),
- selection: rgba(0x8f40713d).into(),
+ cursor: rgba(0xd3869bff).into(),
+ background: rgba(0xd3869bff).into(),
+ selection: rgba(0xd3869b3d).into(),
},
PlayerColor {
- cursor: rgba(0x437b59ff).into(),
- background: rgba(0x437b59ff).into(),
- selection: rgba(0x437b593d).into(),
+ cursor: rgba(0x8ec07cff).into(),
+ background: rgba(0x8ec07cff).into(),
+ selection: rgba(0x8ec07c3d).into(),
},
PlayerColor {
- cursor: rgba(0x9d0408ff).into(),
- background: rgba(0x9d0408ff).into(),
- selection: rgba(0x9d04083d).into(),
+ cursor: rgba(0xfb4a35ff).into(),
+ background: rgba(0xfb4a35ff).into(),
+ selection: rgba(0xfb4a353d).into(),
},
PlayerColor {
- cursor: rgba(0xb57616ff).into(),
- background: rgba(0xb57616ff).into(),
- selection: rgba(0xb576163d).into(),
+ cursor: rgba(0xf9bd30ff).into(),
+ background: rgba(0xf9bd30ff).into(),
+ selection: rgba(0xf9bd303d).into(),
},
PlayerColor {
- cursor: rgba(0x797410ff).into(),
- background: rgba(0x797410ff).into(),
- selection: rgba(0x7974103d).into(),
+ cursor: rgba(0xb8bb27ff).into(),
+ background: rgba(0xb8bb27ff).into(),
+ selection: rgba(0xb8bb273d).into(),
},
])),
syntax: Some(UserSyntaxTheme {
@@ -187,63 +187,63 @@ pub fn gruvbox() -> UserThemeFamily {
(
"attribute".into(),
UserHighlightStyle {
- color: Some(rgba(0x0b6678ff).into()),
+ color: Some(rgba(0x83a598ff).into()),
..Default::default()
},
),
(
"boolean".into(),
UserHighlightStyle {
- color: Some(rgba(0x8f3f71ff).into()),
+ color: Some(rgba(0xd3869bff).into()),
..Default::default()
},
),
(
"comment".into(),
UserHighlightStyle {
- color: Some(rgba(0x7c6f64ff).into()),
+ color: Some(rgba(0xa89984ff).into()),
..Default::default()
},
),
(
"comment.doc".into(),
UserHighlightStyle {
- color: Some(rgba(0x5d544eff).into()),
+ color: Some(rgba(0xc7b798ff).into()),
..Default::default()
},
),
(
"constant".into(),
UserHighlightStyle {
- color: Some(rgba(0xb57614ff).into()),
+ color: Some(rgba(0xfabd2fff).into()),
..Default::default()
},
),
(
"constructor".into(),
UserHighlightStyle {
- color: Some(rgba(0x0b6678ff).into()),
+ color: Some(rgba(0x83a598ff).into()),
..Default::default()
},
),
(
"embedded".into(),
UserHighlightStyle {
- color: Some(rgba(0x427b58ff).into()),
+ color: Some(rgba(0x8ec07cff).into()),
..Default::default()
},
),
(
"emphasis".into(),
UserHighlightStyle {
- color: Some(rgba(0x0b6678ff).into()),
+ color: Some(rgba(0x83a598ff).into()),
..Default::default()
},
),
(
"emphasis.strong".into(),
UserHighlightStyle {
- color: Some(rgba(0x0b6678ff).into()),
+ color: Some(rgba(0x83a598ff).into()),
font_weight: Some(UserFontWeight(700.0)),
..Default::default()
},
@@ -251,28 +251,28 @@ pub fn gruvbox() -> UserThemeFamily {
(
"enum".into(),
UserHighlightStyle {
- color: Some(rgba(0xaf3a03ff).into()),
+ color: Some(rgba(0xfe8019ff).into()),
..Default::default()
},
),
(
"function".into(),
UserHighlightStyle {
- color: Some(rgba(0x79740eff).into()),
+ color: Some(rgba(0xb8bb26ff).into()),
..Default::default()
},
),
(
"function.builtin".into(),
UserHighlightStyle {
- color: Some(rgba(0x9d0006ff).into()),
+ color: Some(rgba(0xfb4934ff).into()),
..Default::default()
},
),
(
"hint".into(),
UserHighlightStyle {
- color: Some(rgba(0x677562ff).into()),
+ color: Some(rgba(0x8d957eff).into()),
font_weight: Some(UserFontWeight(700.0)),
..Default::default()
},
@@ -280,21 +280,21 @@ pub fn gruvbox() -> UserThemeFamily {
(
"keyword".into(),
UserHighlightStyle {
- color: Some(rgba(0x9d0006ff).into()),
+ color: Some(rgba(0xfb4934ff).into()),
..Default::default()
},
),
(
"label".into(),
UserHighlightStyle {
- color: Some(rgba(0x0b6678ff).into()),
+ color: Some(rgba(0x83a598ff).into()),
..Default::default()
},
),
(
"link_text".into(),
UserHighlightStyle {
- color: Some(rgba(0x427b58ff).into()),
+ color: Some(rgba(0x8ec07cff).into()),
font_style: Some(UserFontStyle::Italic),
..Default::default()
},
@@ -302,28 +302,28 @@ pub fn gruvbox() -> UserThemeFamily {
(
"link_uri".into(),
UserHighlightStyle {
- color: Some(rgba(0x8f3f71ff).into()),
+ color: Some(rgba(0xd3869bff).into()),
..Default::default()
},
),
(
"number".into(),
UserHighlightStyle {
- color: Some(rgba(0x8f3f71ff).into()),
+ color: Some(rgba(0xd3869bff).into()),
..Default::default()
},
),
(
"operator".into(),
UserHighlightStyle {
- color: Some(rgba(0x427b58ff).into()),
+ color: Some(rgba(0x8ec07cff).into()),
..Default::default()
},
),
(
"predictive".into(),
UserHighlightStyle {
- color: Some(rgba(0x7d9881ff).into()),
+ color: Some(rgba(0x717363ff).into()),
font_style: Some(UserFontStyle::Italic),
..Default::default()
},
@@ -331,112 +331,112 @@ pub fn gruvbox() -> UserThemeFamily {
(
"preproc".into(),
UserHighlightStyle {
- color: Some(rgba(0x282828ff).into()),
+ color: Some(rgba(0xfbf1c7ff).into()),
..Default::default()
},
),
(
"primary".into(),
UserHighlightStyle {
- color: Some(rgba(0x282828ff).into()),
+ color: Some(rgba(0xebdbb2ff).into()),
..Default::default()
},
),
(
"property".into(),
UserHighlightStyle {
- color: Some(rgba(0x282828ff).into()),
+ color: Some(rgba(0xebdbb2ff).into()),
..Default::default()
},
),
(
"punctuation".into(),
UserHighlightStyle {
- color: Some(rgba(0x3c3836ff).into()),
+ color: Some(rgba(0xd5c4a1ff).into()),
..Default::default()
},
),
(
"punctuation.bracket".into(),
UserHighlightStyle {
- color: Some(rgba(0x665c54ff).into()),
+ color: Some(rgba(0xa89984ff).into()),
..Default::default()
},
),
(
"punctuation.delimiter".into(),
UserHighlightStyle {
- color: Some(rgba(0x413d3aff).into()),
+ color: Some(rgba(0xe5d5adff).into()),
..Default::default()
},
),
(
"punctuation.list_marker".into(),
UserHighlightStyle {
- color: Some(rgba(0x282828ff).into()),
+ color: Some(rgba(0xebdbb2ff).into()),
..Default::default()
},
),
(
"punctuation.special".into(),
UserHighlightStyle {
- color: Some(rgba(0x413d3aff).into()),
+ color: Some(rgba(0xe5d5adff).into()),
..Default::default()
},
),
(
"string".into(),
UserHighlightStyle {
- color: Some(rgba(0x79740eff).into()),
+ color: Some(rgba(0xb8bb26ff).into()),
..Default::default()
},
),
(
"string.escape".into(),
UserHighlightStyle {
- color: Some(rgba(0x5d544eff).into()),
+ color: Some(rgba(0xc7b798ff).into()),
..Default::default()
},
),
(
"string.regex".into(),
UserHighlightStyle {
- color: Some(rgba(0xaf3a03ff).into()),
+ color: Some(rgba(0xfe8019ff).into()),
..Default::default()
},
),
(
"string.special".into(),
UserHighlightStyle {
- color: Some(rgba(0x8f3f71ff).into()),
+ color: Some(rgba(0xd3869bff).into()),
..Default::default()
},
),
(
"string.special.symbol".into(),
UserHighlightStyle {
- color: Some(rgba(0x427b58ff).into()),
+ color: Some(rgba(0x8ec07cff).into()),
..Default::default()
},
),
(
"tag".into(),
UserHighlightStyle {
- color: Some(rgba(0x427b58ff).into()),
+ color: Some(rgba(0x8ec07cff).into()),
..Default::default()
},
),
(
"text.literal".into(),
UserHighlightStyle {
- color: Some(rgba(0x076678ff).into()),
+ color: Some(rgba(0x83a598ff).into()),
..Default::default()
},
),
(
"title".into(),
UserHighlightStyle {
- color: Some(rgba(0x79740eff).into()),
+ color: Some(rgba(0xb8bb26ff).into()),
font_weight: Some(UserFontWeight(700.0)),
..Default::default()
},
@@ -444,21 +444,21 @@ pub fn gruvbox() -> UserThemeFamily {
(
"type".into(),
UserHighlightStyle {
- color: Some(rgba(0xb57614ff).into()),
+ color: Some(rgba(0xfabd2fff).into()),
..Default::default()
},
),
(
"variable".into(),
UserHighlightStyle {
- color: Some(rgba(0x076678ff).into()),
+ color: Some(rgba(0x83a598ff).into()),
..Default::default()
},
),
(
"variant".into(),
UserHighlightStyle {
- color: Some(rgba(0x0b6678ff).into()),
+ color: Some(rgba(0x83a598ff).into()),
..Default::default()
},
),
@@ -467,7 +467,7 @@ pub fn gruvbox() -> UserThemeFamily {
},
},
UserTheme {
- name: "Gruvbox Dark Soft".into(),
+ name: "Gruvbox Dark Hard".into(),
appearance: Appearance::Dark,
styles: UserThemeStylesRefinement {
colors: ThemeColorsRefinement {
@@ -477,21 +477,21 @@ pub fn gruvbox() -> UserThemeFamily {
border_selected: Some(rgba(0x303a36ff).into()),
border_transparent: Some(rgba(0x00000000).into()),
border_disabled: Some(rgba(0x544c48ff).into()),
- elevated_surface_background: Some(rgba(0x3b3735ff).into()),
- surface_background: Some(rgba(0x3b3735ff).into()),
+ elevated_surface_background: Some(rgba(0x393634ff).into()),
+ surface_background: Some(rgba(0x393634ff).into()),
background: Some(rgba(0x4c4642ff).into()),
- panel_background: Some(rgba(0x3b3735ff).into()),
- element_background: Some(rgba(0x3b3735ff).into()),
+ panel_background: Some(rgba(0x393634ff).into()),
+ element_background: Some(rgba(0x393634ff).into()),
element_hover: Some(rgba(0x494340ff).into()),
element_active: Some(rgba(0x5b524cff).into()),
element_selected: Some(rgba(0x5b524cff).into()),
- element_disabled: Some(rgba(0x3b3735ff).into()),
+ element_disabled: Some(rgba(0x393634ff).into()),
drop_target_background: Some(rgba(0xc5b59780).into()),
ghost_element_background: Some(rgba(0x00000000).into()),
ghost_element_hover: Some(rgba(0x494340ff).into()),
ghost_element_active: Some(rgba(0x5b524cff).into()),
ghost_element_selected: Some(rgba(0x5b524cff).into()),
- ghost_element_disabled: Some(rgba(0x3b3735ff).into()),
+ ghost_element_disabled: Some(rgba(0x393634ff).into()),
text: Some(rgba(0xfbf1c7ff).into()),
text_muted: Some(rgba(0xc5b597ff).into()),
text_placeholder: Some(rgba(0x9a8c79ff).into()),
@@ -504,21 +504,21 @@ pub fn gruvbox() -> UserThemeFamily {
icon_accent: Some(rgba(0x83a598ff).into()),
status_bar_background: Some(rgba(0x4c4642ff).into()),
title_bar_background: Some(rgba(0x4c4642ff).into()),
- toolbar_background: Some(rgba(0x32302fff).into()),
- tab_bar_background: Some(rgba(0x3b3735ff).into()),
- tab_inactive_background: Some(rgba(0x3b3735ff).into()),
- tab_active_background: Some(rgba(0x32302fff).into()),
+ toolbar_background: Some(rgba(0x1d2021ff).into()),
+ tab_bar_background: Some(rgba(0x393634ff).into()),
+ tab_inactive_background: Some(rgba(0x393634ff).into()),
+ tab_active_background: Some(rgba(0x1d2021ff).into()),
scrollbar_thumb_background: Some(rgba(0xfbf1c74c).into()),
scrollbar_thumb_hover_background: Some(rgba(0x494340ff).into()),
scrollbar_thumb_border: Some(rgba(0x494340ff).into()),
scrollbar_track_background: Some(rgba(0x00000000).into()),
- scrollbar_track_border: Some(rgba(0x393634ff).into()),
+ scrollbar_track_border: Some(rgba(0x343130ff).into()),
editor_foreground: Some(rgba(0xebdbb2ff).into()),
- editor_background: Some(rgba(0x32302fff).into()),
- editor_gutter_background: Some(rgba(0x32302fff).into()),
- editor_subheader_background: Some(rgba(0x3b3735ff).into()),
- editor_active_line_background: Some(rgba(0x3b3735bf).into()),
- editor_highlighted_line_background: Some(rgba(0x3b3735ff).into()),
+ editor_background: Some(rgba(0x1d2021ff).into()),
+ editor_gutter_background: Some(rgba(0x1d2021ff).into()),
+ editor_subheader_background: Some(rgba(0x393634ff).into()),
+ editor_active_line_background: Some(rgba(0x393634bf).into()),
+ editor_highlighted_line_background: Some(rgba(0x393634ff).into()),
editor_line_number: Some(rgba(0xfbf1c759).into()),
editor_active_line_number: Some(rgba(0xfbf1c7ff).into()),
editor_invisible: Some(rgba(0xc5b597ff).into()),
@@ -526,7 +526,7 @@ pub fn gruvbox() -> UserThemeFamily {
editor_active_wrap_guide: Some(rgba(0xfbf1c71a).into()),
editor_document_highlight_read_background: Some(rgba(0x83a5981a).into()),
editor_document_highlight_write_background: Some(rgba(0x92847466).into()),
- terminal_background: Some(rgba(0x32302fff).into()),
+ terminal_background: Some(rgba(0x1d2021ff).into()),
terminal_ansi_bright_black: Some(rgba(0x73675eff).into()),
terminal_ansi_bright_red: Some(rgba(0x93211eff).into()),
terminal_ansi_bright_green: Some(rgba(0x615d1bff).into()),
@@ -535,7 +535,7 @@ pub fn gruvbox() -> UserThemeFamily {
terminal_ansi_bright_magenta: Some(rgba(0x514a41ff).into()),
terminal_ansi_bright_cyan: Some(rgba(0x45603eff).into()),
terminal_ansi_bright_white: Some(rgba(0xfbf1c7ff).into()),
- terminal_ansi_black: Some(rgba(0x32302fff).into()),
+ terminal_ansi_black: Some(rgba(0x1d2021ff).into()),
terminal_ansi_red: Some(rgba(0xfb4a35ff).into()),
terminal_ansi_green: Some(rgba(0xb8bb27ff).into()),
terminal_ansi_yellow: Some(rgba(0xf9bd30ff).into()),
@@ -918,170 +918,170 @@ pub fn gruvbox() -> UserThemeFamily {
},
},
UserTheme {
- name: "Gruvbox Light".into(),
- appearance: Appearance::Light,
+ name: "Gruvbox Dark Soft".into(),
+ appearance: Appearance::Dark,
styles: UserThemeStylesRefinement {
colors: ThemeColorsRefinement {
- border: Some(rgba(0xc9b99aff).into()),
- border_variant: Some(rgba(0xddcca7ff).into()),
- border_focused: Some(rgba(0xaec6cdff).into()),
- border_selected: Some(rgba(0xaec6cdff).into()),
+ border: Some(rgba(0x5b534dff).into()),
+ border_variant: Some(rgba(0x494340ff).into()),
+ border_focused: Some(rgba(0x303a36ff).into()),
+ border_selected: Some(rgba(0x303a36ff).into()),
border_transparent: Some(rgba(0x00000000).into()),
- border_disabled: Some(rgba(0xd1c09eff).into()),
- elevated_surface_background: Some(rgba(0xecddb4ff).into()),
- surface_background: Some(rgba(0xecddb4ff).into()),
- background: Some(rgba(0xd9c8a4ff).into()),
- panel_background: Some(rgba(0xecddb4ff).into()),
- element_background: Some(rgba(0xecddb4ff).into()),
- element_hover: Some(rgba(0xddcca7ff).into()),
- element_active: Some(rgba(0xc9b99aff).into()),
- element_selected: Some(rgba(0xc9b99aff).into()),
- element_disabled: Some(rgba(0xecddb4ff).into()),
- drop_target_background: Some(rgba(0x5f565080).into()),
+ border_disabled: Some(rgba(0x544c48ff).into()),
+ elevated_surface_background: Some(rgba(0x3b3735ff).into()),
+ surface_background: Some(rgba(0x3b3735ff).into()),
+ background: Some(rgba(0x4c4642ff).into()),
+ panel_background: Some(rgba(0x3b3735ff).into()),
+ element_background: Some(rgba(0x3b3735ff).into()),
+ element_hover: Some(rgba(0x494340ff).into()),
+ element_active: Some(rgba(0x5b524cff).into()),
+ element_selected: Some(rgba(0x5b524cff).into()),
+ element_disabled: Some(rgba(0x3b3735ff).into()),
+ drop_target_background: Some(rgba(0xc5b59780).into()),
ghost_element_background: Some(rgba(0x00000000).into()),
- ghost_element_hover: Some(rgba(0xddcca7ff).into()),
- ghost_element_active: Some(rgba(0xc9b99aff).into()),
- ghost_element_selected: Some(rgba(0xc9b99aff).into()),
- ghost_element_disabled: Some(rgba(0xecddb4ff).into()),
- text: Some(rgba(0x282828ff).into()),
- text_muted: Some(rgba(0x5f5650ff).into()),
- text_placeholder: Some(rgba(0x8a7c6fff).into()),
- text_disabled: Some(rgba(0x8a7c6fff).into()),
- text_accent: Some(rgba(0x0b6678ff).into()),
- icon: Some(rgba(0x282828ff).into()),
- icon_muted: Some(rgba(0x5f5650ff).into()),
- icon_disabled: Some(rgba(0x8a7c6fff).into()),
- icon_placeholder: Some(rgba(0x5f5650ff).into()),
- icon_accent: Some(rgba(0x0b6678ff).into()),
- status_bar_background: Some(rgba(0xd9c8a4ff).into()),
- title_bar_background: Some(rgba(0xd9c8a4ff).into()),
- toolbar_background: Some(rgba(0xfbf1c7ff).into()),
- tab_bar_background: Some(rgba(0xecddb4ff).into()),
- tab_inactive_background: Some(rgba(0xecddb4ff).into()),
- tab_active_background: Some(rgba(0xfbf1c7ff).into()),
- scrollbar_thumb_background: Some(rgba(0x2828284c).into()),
- scrollbar_thumb_hover_background: Some(rgba(0xddcca7ff).into()),
- scrollbar_thumb_border: Some(rgba(0xddcca7ff).into()),
+ ghost_element_hover: Some(rgba(0x494340ff).into()),
+ ghost_element_active: Some(rgba(0x5b524cff).into()),
+ ghost_element_selected: Some(rgba(0x5b524cff).into()),
+ ghost_element_disabled: Some(rgba(0x3b3735ff).into()),
+ text: Some(rgba(0xfbf1c7ff).into()),
+ text_muted: Some(rgba(0xc5b597ff).into()),
+ text_placeholder: Some(rgba(0x9a8c79ff).into()),
+ text_disabled: Some(rgba(0x9a8c79ff).into()),
+ text_accent: Some(rgba(0x83a598ff).into()),
+ icon: Some(rgba(0xfbf1c7ff).into()),
+ icon_muted: Some(rgba(0xc5b597ff).into()),
+ icon_disabled: Some(rgba(0x9a8c79ff).into()),
+ icon_placeholder: Some(rgba(0xc5b597ff).into()),
+ icon_accent: Some(rgba(0x83a598ff).into()),
+ status_bar_background: Some(rgba(0x4c4642ff).into()),
+ title_bar_background: Some(rgba(0x4c4642ff).into()),
+ toolbar_background: Some(rgba(0x32302fff).into()),
+ tab_bar_background: Some(rgba(0x3b3735ff).into()),
+ tab_inactive_background: Some(rgba(0x3b3735ff).into()),
+ tab_active_background: Some(rgba(0x32302fff).into()),
+ scrollbar_thumb_background: Some(rgba(0xfbf1c74c).into()),
+ scrollbar_thumb_hover_background: Some(rgba(0x494340ff).into()),
+ scrollbar_thumb_border: Some(rgba(0x494340ff).into()),
scrollbar_track_background: Some(rgba(0x00000000).into()),
- scrollbar_track_border: Some(rgba(0xefe1b8ff).into()),
- editor_foreground: Some(rgba(0x282828ff).into()),
- editor_background: Some(rgba(0xfbf1c7ff).into()),
- editor_gutter_background: Some(rgba(0xfbf1c7ff).into()),
- editor_subheader_background: Some(rgba(0xecddb4ff).into()),
- editor_active_line_background: Some(rgba(0xecddb4bf).into()),
- editor_highlighted_line_background: Some(rgba(0xecddb4ff).into()),
- editor_line_number: Some(rgba(0x28282859).into()),
- editor_active_line_number: Some(rgba(0x282828ff).into()),
- editor_invisible: Some(rgba(0x5f5650ff).into()),
- editor_wrap_guide: Some(rgba(0x2828280d).into()),
- editor_active_wrap_guide: Some(rgba(0x2828281a).into()),
- editor_document_highlight_read_background: Some(rgba(0x0b66781a).into()),
+ scrollbar_track_border: Some(rgba(0x393634ff).into()),
+ editor_foreground: Some(rgba(0xebdbb2ff).into()),
+ editor_background: Some(rgba(0x32302fff).into()),
+ editor_gutter_background: Some(rgba(0x32302fff).into()),
+ editor_subheader_background: Some(rgba(0x3b3735ff).into()),
+ editor_active_line_background: Some(rgba(0x3b3735bf).into()),
+ editor_highlighted_line_background: Some(rgba(0x3b3735ff).into()),
+ editor_line_number: Some(rgba(0xfbf1c759).into()),
+ editor_active_line_number: Some(rgba(0xfbf1c7ff).into()),
+ editor_invisible: Some(rgba(0xc5b597ff).into()),
+ editor_wrap_guide: Some(rgba(0xfbf1c70d).into()),
+ editor_active_wrap_guide: Some(rgba(0xfbf1c71a).into()),
+ editor_document_highlight_read_background: Some(rgba(0x83a5981a).into()),
editor_document_highlight_write_background: Some(rgba(0x92847466).into()),
- terminal_background: Some(rgba(0xfbf1c7ff).into()),
- terminal_ansi_bright_black: Some(rgba(0xb1a28aff).into()),
- terminal_ansi_bright_red: Some(rgba(0xdc8c7bff).into()),
- terminal_ansi_bright_green: Some(rgba(0xbfb787ff).into()),
- terminal_ansi_bright_yellow: Some(rgba(0xe2b88bff).into()),
- terminal_ansi_bright_blue: Some(rgba(0x8fb0baff).into()),
- terminal_ansi_bright_magenta: Some(rgba(0xbcb5afff).into()),
- terminal_ansi_bright_cyan: Some(rgba(0x9fbca8ff).into()),
- terminal_ansi_bright_white: Some(rgba(0x282828ff).into()),
- terminal_ansi_black: Some(rgba(0xfbf1c7ff).into()),
- terminal_ansi_red: Some(rgba(0x9d0408ff).into()),
- terminal_ansi_green: Some(rgba(0x797410ff).into()),
- terminal_ansi_yellow: Some(rgba(0xb57616ff).into()),
- terminal_ansi_blue: Some(rgba(0x0b6678ff).into()),
- terminal_ansi_magenta: Some(rgba(0x7c6f64ff).into()),
- terminal_ansi_cyan: Some(rgba(0x437b59ff).into()),
- terminal_ansi_white: Some(rgba(0x282828ff).into()),
- link_text_hover: Some(rgba(0x0b6678ff).into()),
+ terminal_background: Some(rgba(0x32302fff).into()),
+ terminal_ansi_bright_black: Some(rgba(0x73675eff).into()),
+ terminal_ansi_bright_red: Some(rgba(0x93211eff).into()),
+ terminal_ansi_bright_green: Some(rgba(0x615d1bff).into()),
+ terminal_ansi_bright_yellow: Some(rgba(0x91611cff).into()),
+ terminal_ansi_bright_blue: Some(rgba(0x414f4aff).into()),
+ terminal_ansi_bright_magenta: Some(rgba(0x514a41ff).into()),
+ terminal_ansi_bright_cyan: Some(rgba(0x45603eff).into()),
+ terminal_ansi_bright_white: Some(rgba(0xfbf1c7ff).into()),
+ terminal_ansi_black: Some(rgba(0x32302fff).into()),
+ terminal_ansi_red: Some(rgba(0xfb4a35ff).into()),
+ terminal_ansi_green: Some(rgba(0xb8bb27ff).into()),
+ terminal_ansi_yellow: Some(rgba(0xf9bd30ff).into()),
+ terminal_ansi_blue: Some(rgba(0x83a598ff).into()),
+ terminal_ansi_magenta: Some(rgba(0xa89984ff).into()),
+ terminal_ansi_cyan: Some(rgba(0x8ec07cff).into()),
+ terminal_ansi_white: Some(rgba(0xfbf1c7ff).into()),
+ link_text_hover: Some(rgba(0x83a598ff).into()),
..Default::default()
},
status: StatusColorsRefinement {
- conflict: Some(rgba(0xb57616ff).into()),
- conflict_background: Some(rgba(0xf5e2d0ff).into()),
- conflict_border: Some(rgba(0xebccabff).into()),
- created: Some(rgba(0x797410ff).into()),
- created_background: Some(rgba(0xe5e1ceff).into()),
- created_border: Some(rgba(0xd1cba8ff).into()),
- deleted: Some(rgba(0x9d0408ff).into()),
- deleted_background: Some(rgba(0xf4d1c9ff).into()),
- deleted_border: Some(rgba(0xe8ac9eff).into()),
- error: Some(rgba(0x9d0408ff).into()),
- error_background: Some(rgba(0xf4d1c9ff).into()),
- error_border: Some(rgba(0xe8ac9eff).into()),
- hidden: Some(rgba(0x8a7c6fff).into()),
- hidden_background: Some(rgba(0xd9c8a4ff).into()),
- hidden_border: Some(rgba(0xd1c09eff).into()),
- hint: Some(rgba(0x677562ff).into()),
- hint_background: Some(rgba(0xd2dee2ff).into()),
- hint_border: Some(rgba(0xaec6cdff).into()),
- ignored: Some(rgba(0x5f5650ff).into()),
- ignored_background: Some(rgba(0xd9c8a4ff).into()),
- ignored_border: Some(rgba(0xc9b99aff).into()),
- info: Some(rgba(0x0b6678ff).into()),
- info_background: Some(rgba(0xd2dee2ff).into()),
- info_border: Some(rgba(0xaec6cdff).into()),
- modified: Some(rgba(0xb57616ff).into()),
- modified_background: Some(rgba(0xf5e2d0ff).into()),
- modified_border: Some(rgba(0xebccabff).into()),
- predictive: Some(rgba(0x7d9881ff).into()),
- predictive_background: Some(rgba(0xe5e1ceff).into()),
- predictive_border: Some(rgba(0xd1cba8ff).into()),
- renamed: Some(rgba(0x0b6678ff).into()),
- renamed_background: Some(rgba(0xd2dee2ff).into()),
- renamed_border: Some(rgba(0xaec6cdff).into()),
- success: Some(rgba(0x797410ff).into()),
- success_background: Some(rgba(0xe5e1ceff).into()),
- success_border: Some(rgba(0xd1cba8ff).into()),
- unreachable: Some(rgba(0x5f5650ff).into()),
- unreachable_background: Some(rgba(0xd9c8a4ff).into()),
- unreachable_border: Some(rgba(0xc9b99aff).into()),
- warning: Some(rgba(0xb57616ff).into()),
- warning_background: Some(rgba(0xf5e2d0ff).into()),
- warning_border: Some(rgba(0xebccabff).into()),
+ conflict: Some(rgba(0xf9bd30ff).into()),
+ conflict_background: Some(rgba(0x582f10ff).into()),
+ conflict_border: Some(rgba(0x754916ff).into()),
+ created: Some(rgba(0xb8bb27ff).into()),
+ created_background: Some(rgba(0x332b11ff).into()),
+ created_border: Some(rgba(0x4a4516ff).into()),
+ deleted: Some(rgba(0xfb4a35ff).into()),
+ deleted_background: Some(rgba(0x5a0a10ff).into()),
+ deleted_border: Some(rgba(0x771618ff).into()),
+ error: Some(rgba(0xfb4a35ff).into()),
+ error_background: Some(rgba(0x5a0a10ff).into()),
+ error_border: Some(rgba(0x771618ff).into()),
+ hidden: Some(rgba(0x9a8c79ff).into()),
+ hidden_background: Some(rgba(0x4c4642ff).into()),
+ hidden_border: Some(rgba(0x544c48ff).into()),
+ hint: Some(rgba(0x8d957eff).into()),
+ hint_background: Some(rgba(0x1e2321ff).into()),
+ hint_border: Some(rgba(0x303a36ff).into()),
+ ignored: Some(rgba(0xc5b597ff).into()),
+ ignored_background: Some(rgba(0x4c4642ff).into()),
+ ignored_border: Some(rgba(0x5b534dff).into()),
+ info: Some(rgba(0x83a598ff).into()),
+ info_background: Some(rgba(0x1e2321ff).into()),
+ info_border: Some(rgba(0x303a36ff).into()),
+ modified: Some(rgba(0xf9bd30ff).into()),
+ modified_background: Some(rgba(0x582f10ff).into()),
+ modified_border: Some(rgba(0x754916ff).into()),
+ predictive: Some(rgba(0x717363ff).into()),
+ predictive_background: Some(rgba(0x332b11ff).into()),
+ predictive_border: Some(rgba(0x4a4516ff).into()),
+ renamed: Some(rgba(0x83a598ff).into()),
+ renamed_background: Some(rgba(0x1e2321ff).into()),
+ renamed_border: Some(rgba(0x303a36ff).into()),
+ success: Some(rgba(0xb8bb27ff).into()),
+ success_background: Some(rgba(0x332b11ff).into()),
+ success_border: Some(rgba(0x4a4516ff).into()),
+ unreachable: Some(rgba(0xc5b597ff).into()),
+ unreachable_background: Some(rgba(0x4c4642ff).into()),
+ unreachable_border: Some(rgba(0x5b534dff).into()),
+ warning: Some(rgba(0xf9bd30ff).into()),
+ warning_background: Some(rgba(0x582f10ff).into()),
+ warning_border: Some(rgba(0x754916ff).into()),
..Default::default()
},
player: Some(PlayerColors(vec![
PlayerColor {
- cursor: rgba(0x0b6678ff).into(),
- background: rgba(0x0b6678ff).into(),
- selection: rgba(0x0b66783d).into(),
+ cursor: rgba(0x83a598ff).into(),
+ background: rgba(0x83a598ff).into(),
+ selection: rgba(0x83a5983d).into(),
},
PlayerColor {
- cursor: rgba(0x7c6f64ff).into(),
- background: rgba(0x7c6f64ff).into(),
- selection: rgba(0x7c6f643d).into(),
+ cursor: rgba(0xa89984ff).into(),
+ background: rgba(0xa89984ff).into(),
+ selection: rgba(0xa899843d).into(),
},
PlayerColor {
- cursor: rgba(0xaf3b05ff).into(),
- background: rgba(0xaf3b05ff).into(),
- selection: rgba(0xaf3b053d).into(),
+ cursor: rgba(0xfd801bff).into(),
+ background: rgba(0xfd801bff).into(),
+ selection: rgba(0xfd801b3d).into(),
},
PlayerColor {
- cursor: rgba(0x8f4071ff).into(),
- background: rgba(0x8f4071ff).into(),
- selection: rgba(0x8f40713d).into(),
+ cursor: rgba(0xd3869bff).into(),
+ background: rgba(0xd3869bff).into(),
+ selection: rgba(0xd3869b3d).into(),
},
PlayerColor {
- cursor: rgba(0x437b59ff).into(),
- background: rgba(0x437b59ff).into(),
- selection: rgba(0x437b593d).into(),
+ cursor: rgba(0x8ec07cff).into(),
+ background: rgba(0x8ec07cff).into(),
+ selection: rgba(0x8ec07c3d).into(),
},
PlayerColor {
- cursor: rgba(0x9d0408ff).into(),
- background: rgba(0x9d0408ff).into(),
- selection: rgba(0x9d04083d).into(),
+ cursor: rgba(0xfb4a35ff).into(),
+ background: rgba(0xfb4a35ff).into(),
+ selection: rgba(0xfb4a353d).into(),
},
PlayerColor {
- cursor: rgba(0xb57616ff).into(),
- background: rgba(0xb57616ff).into(),
- selection: rgba(0xb576163d).into(),
+ cursor: rgba(0xf9bd30ff).into(),
+ background: rgba(0xf9bd30ff).into(),
+ selection: rgba(0xf9bd303d).into(),
},
PlayerColor {
- cursor: rgba(0x797410ff).into(),
- background: rgba(0x797410ff).into(),
- selection: rgba(0x7974103d).into(),
+ cursor: rgba(0xb8bb27ff).into(),
+ background: rgba(0xb8bb27ff).into(),
+ selection: rgba(0xb8bb273d).into(),
},
])),
syntax: Some(UserSyntaxTheme {
@@ -16,160 +16,160 @@ pub fn one() -> UserThemeFamily {
author: "Zed Industries".into(),
themes: vec![
UserTheme {
- name: "One Light".into(),
- appearance: Appearance::Light,
+ name: "One Dark".into(),
+ appearance: Appearance::Dark,
styles: UserThemeStylesRefinement {
colors: ThemeColorsRefinement {
- border: Some(rgba(0xc9c9caff).into()),
- border_variant: Some(rgba(0xdfdfe0ff).into()),
- border_focused: Some(rgba(0xcbcdf6ff).into()),
- border_selected: Some(rgba(0xcbcdf6ff).into()),
+ border: Some(rgba(0x464b57ff).into()),
+ border_variant: Some(rgba(0x363c46ff).into()),
+ border_focused: Some(rgba(0x293c5bff).into()),
+ border_selected: Some(rgba(0x293c5bff).into()),
border_transparent: Some(rgba(0x00000000).into()),
- border_disabled: Some(rgba(0xd3d3d4ff).into()),
- elevated_surface_background: Some(rgba(0xebebecff).into()),
- surface_background: Some(rgba(0xebebecff).into()),
- background: Some(rgba(0xdcdcddff).into()),
- panel_background: Some(rgba(0xebebecff).into()),
- element_background: Some(rgba(0xebebecff).into()),
- element_hover: Some(rgba(0xdfdfe0ff).into()),
- element_active: Some(rgba(0xcacacaff).into()),
- element_selected: Some(rgba(0xcacacaff).into()),
- element_disabled: Some(rgba(0xebebecff).into()),
- drop_target_background: Some(rgba(0x7f818880).into()),
+ border_disabled: Some(rgba(0x414754ff).into()),
+ elevated_surface_background: Some(rgba(0x2f343eff).into()),
+ surface_background: Some(rgba(0x2f343eff).into()),
+ background: Some(rgba(0x3b414dff).into()),
+ panel_background: Some(rgba(0x2f343eff).into()),
+ element_background: Some(rgba(0x2f343eff).into()),
+ element_hover: Some(rgba(0x363c46ff).into()),
+ element_active: Some(rgba(0x454a56ff).into()),
+ element_selected: Some(rgba(0x454a56ff).into()),
+ element_disabled: Some(rgba(0x2f343eff).into()),
+ drop_target_background: Some(rgba(0x83899480).into()),
ghost_element_background: Some(rgba(0x00000000).into()),
- ghost_element_hover: Some(rgba(0xdfdfe0ff).into()),
- ghost_element_active: Some(rgba(0xcacacaff).into()),
- ghost_element_selected: Some(rgba(0xcacacaff).into()),
- ghost_element_disabled: Some(rgba(0xebebecff).into()),
- text: Some(rgba(0x383a41ff).into()),
- text_muted: Some(rgba(0x7f8188ff).into()),
- text_placeholder: Some(rgba(0xa1a1a3ff).into()),
- text_disabled: Some(rgba(0xa1a1a3ff).into()),
- text_accent: Some(rgba(0x5c79e2ff).into()),
- icon: Some(rgba(0x383a41ff).into()),
- icon_muted: Some(rgba(0x7f8188ff).into()),
- icon_disabled: Some(rgba(0xa1a1a3ff).into()),
- icon_placeholder: Some(rgba(0x7f8188ff).into()),
- icon_accent: Some(rgba(0x5c79e2ff).into()),
- status_bar_background: Some(rgba(0xdcdcddff).into()),
- title_bar_background: Some(rgba(0xdcdcddff).into()),
- toolbar_background: Some(rgba(0xfafafaff).into()),
- tab_bar_background: Some(rgba(0xebebecff).into()),
- tab_inactive_background: Some(rgba(0xebebecff).into()),
- tab_active_background: Some(rgba(0xfafafaff).into()),
- scrollbar_thumb_background: Some(rgba(0x383a414c).into()),
- scrollbar_thumb_hover_background: Some(rgba(0xdfdfe0ff).into()),
- scrollbar_thumb_border: Some(rgba(0xdfdfe0ff).into()),
+ ghost_element_hover: Some(rgba(0x363c46ff).into()),
+ ghost_element_active: Some(rgba(0x454a56ff).into()),
+ ghost_element_selected: Some(rgba(0x454a56ff).into()),
+ ghost_element_disabled: Some(rgba(0x2f343eff).into()),
+ text: Some(rgba(0xc8ccd4ff).into()),
+ text_muted: Some(rgba(0x838994ff).into()),
+ text_placeholder: Some(rgba(0x555a63ff).into()),
+ text_disabled: Some(rgba(0x555a63ff).into()),
+ text_accent: Some(rgba(0x74ade8ff).into()),
+ icon: Some(rgba(0xc8ccd4ff).into()),
+ icon_muted: Some(rgba(0x838994ff).into()),
+ icon_disabled: Some(rgba(0x555a63ff).into()),
+ icon_placeholder: Some(rgba(0x838994ff).into()),
+ icon_accent: Some(rgba(0x74ade8ff).into()),
+ status_bar_background: Some(rgba(0x3b414dff).into()),
+ title_bar_background: Some(rgba(0x3b414dff).into()),
+ toolbar_background: Some(rgba(0x282c34ff).into()),
+ tab_bar_background: Some(rgba(0x2f343eff).into()),
+ tab_inactive_background: Some(rgba(0x2f343eff).into()),
+ tab_active_background: Some(rgba(0x282c34ff).into()),
+ scrollbar_thumb_background: Some(rgba(0xc8ccd44c).into()),
+ scrollbar_thumb_hover_background: Some(rgba(0x363c46ff).into()),
+ scrollbar_thumb_border: Some(rgba(0x363c46ff).into()),
scrollbar_track_background: Some(rgba(0x00000000).into()),
- scrollbar_track_border: Some(rgba(0xeeeeeeff).into()),
- editor_foreground: Some(rgba(0x383a41ff).into()),
- editor_background: Some(rgba(0xfafafaff).into()),
- editor_gutter_background: Some(rgba(0xfafafaff).into()),
- editor_subheader_background: Some(rgba(0xebebecff).into()),
- editor_active_line_background: Some(rgba(0xebebecbf).into()),
- editor_highlighted_line_background: Some(rgba(0xebebecff).into()),
- editor_line_number: Some(rgba(0x383a4159).into()),
- editor_active_line_number: Some(rgba(0x383a41ff).into()),
- editor_invisible: Some(rgba(0x7f8188ff).into()),
- editor_wrap_guide: Some(rgba(0x383a410d).into()),
- editor_active_wrap_guide: Some(rgba(0x383a411a).into()),
- editor_document_highlight_read_background: Some(rgba(0x5c79e21a).into()),
- editor_document_highlight_write_background: Some(rgba(0xa3a3a466).into()),
- terminal_background: Some(rgba(0xfafafaff).into()),
- terminal_ansi_bright_black: Some(rgba(0xaaaaaaff).into()),
- terminal_ansi_bright_red: Some(rgba(0xf0b0a4ff).into()),
- terminal_ansi_bright_green: Some(rgba(0xb2cfa9ff).into()),
- terminal_ansi_bright_yellow: Some(rgba(0xf1dfc1ff).into()),
- terminal_ansi_bright_blue: Some(rgba(0xb5baf2ff).into()),
- terminal_ansi_bright_magenta: Some(rgba(0xcea6d3ff).into()),
- terminal_ansi_bright_cyan: Some(rgba(0xa4bfdbff).into()),
- terminal_ansi_bright_white: Some(rgba(0x383a41ff).into()),
- terminal_ansi_black: Some(rgba(0xfafafaff).into()),
- terminal_ansi_red: Some(rgba(0xd36151ff).into()),
- terminal_ansi_green: Some(rgba(0x669f59ff).into()),
+ scrollbar_track_border: Some(rgba(0x2e333cff).into()),
+ editor_foreground: Some(rgba(0xacb2beff).into()),
+ editor_background: Some(rgba(0x282c34ff).into()),
+ editor_gutter_background: Some(rgba(0x282c34ff).into()),
+ editor_subheader_background: Some(rgba(0x2f343eff).into()),
+ editor_active_line_background: Some(rgba(0x2f343ebf).into()),
+ editor_highlighted_line_background: Some(rgba(0x2f343eff).into()),
+ editor_line_number: Some(rgba(0xc8ccd459).into()),
+ editor_active_line_number: Some(rgba(0xc8ccd4ff).into()),
+ editor_invisible: Some(rgba(0x838994ff).into()),
+ editor_wrap_guide: Some(rgba(0xc8ccd40d).into()),
+ editor_active_wrap_guide: Some(rgba(0xc8ccd41a).into()),
+ editor_document_highlight_read_background: Some(rgba(0x74ade81a).into()),
+ editor_document_highlight_write_background: Some(rgba(0x555a6366).into()),
+ terminal_background: Some(rgba(0x282c34ff).into()),
+ terminal_ansi_bright_black: Some(rgba(0x525661ff).into()),
+ terminal_ansi_bright_red: Some(rgba(0x673a3cff).into()),
+ terminal_ansi_bright_green: Some(rgba(0x4d6140ff).into()),
+ terminal_ansi_bright_yellow: Some(rgba(0x786441ff).into()),
+ terminal_ansi_bright_blue: Some(rgba(0x385378ff).into()),
+ terminal_ansi_bright_magenta: Some(rgba(0x5e2b26ff).into()),
+ terminal_ansi_bright_cyan: Some(rgba(0x3a565bff).into()),
+ terminal_ansi_bright_white: Some(rgba(0xc8ccd4ff).into()),
+ terminal_ansi_black: Some(rgba(0x282c34ff).into()),
+ terminal_ansi_red: Some(rgba(0xd07277ff).into()),
+ terminal_ansi_green: Some(rgba(0xa1c181ff).into()),
terminal_ansi_yellow: Some(rgba(0xdec184ff).into()),
- terminal_ansi_blue: Some(rgba(0x5c79e2ff).into()),
- terminal_ansi_magenta: Some(rgba(0x994fa6ff).into()),
- terminal_ansi_cyan: Some(rgba(0x3b82b7ff).into()),
- terminal_ansi_white: Some(rgba(0x383a41ff).into()),
- link_text_hover: Some(rgba(0x5c79e2ff).into()),
+ terminal_ansi_blue: Some(rgba(0x74ade8ff).into()),
+ terminal_ansi_magenta: Some(rgba(0xbe5046ff).into()),
+ terminal_ansi_cyan: Some(rgba(0x6fb4c0ff).into()),
+ terminal_ansi_white: Some(rgba(0xc8ccd4ff).into()),
+ link_text_hover: Some(rgba(0x74ade8ff).into()),
..Default::default()
},
status: StatusColorsRefinement {
conflict: Some(rgba(0xdec184ff).into()),
- conflict_background: Some(rgba(0xfaf2e6ff).into()),
- conflict_border: Some(rgba(0xf5e8d2ff).into()),
- created: Some(rgba(0x669f59ff).into()),
- created_background: Some(rgba(0xe0ebdcff).into()),
- created_border: Some(rgba(0xc8dcc1ff).into()),
- deleted: Some(rgba(0xd36151ff).into()),
- deleted_background: Some(rgba(0xfbdfd9ff).into()),
- deleted_border: Some(rgba(0xf6c6bdff).into()),
- error: Some(rgba(0xd36151ff).into()),
- error_background: Some(rgba(0xfbdfd9ff).into()),
- error_border: Some(rgba(0xf6c6bdff).into()),
- hidden: Some(rgba(0xa1a1a3ff).into()),
- hidden_background: Some(rgba(0xdcdcddff).into()),
- hidden_border: Some(rgba(0xd3d3d4ff).into()),
- hint: Some(rgba(0x9295beff).into()),
- hint_background: Some(rgba(0xe2e2faff).into()),
- hint_border: Some(rgba(0xcbcdf6ff).into()),
- ignored: Some(rgba(0x7f8188ff).into()),
- ignored_background: Some(rgba(0xdcdcddff).into()),
- ignored_border: Some(rgba(0xc9c9caff).into()),
- info: Some(rgba(0x5c79e2ff).into()),
- info_background: Some(rgba(0xe2e2faff).into()),
- info_border: Some(rgba(0xcbcdf6ff).into()),
+ conflict_background: Some(rgba(0x41331dff).into()),
+ conflict_border: Some(rgba(0x5d4c2fff).into()),
+ created: Some(rgba(0xa1c181ff).into()),
+ created_background: Some(rgba(0x222e1dff).into()),
+ created_border: Some(rgba(0x38482fff).into()),
+ deleted: Some(rgba(0xd07277ff).into()),
+ deleted_background: Some(rgba(0x301b1cff).into()),
+ deleted_border: Some(rgba(0x4c2b2cff).into()),
+ error: Some(rgba(0xd07277ff).into()),
+ error_background: Some(rgba(0x301b1cff).into()),
+ error_border: Some(rgba(0x4c2b2cff).into()),
+ hidden: Some(rgba(0x555a63ff).into()),
+ hidden_background: Some(rgba(0x3b414dff).into()),
+ hidden_border: Some(rgba(0x414754ff).into()),
+ hint: Some(rgba(0x5b708aff).into()),
+ hint_background: Some(rgba(0x18243dff).into()),
+ hint_border: Some(rgba(0x293c5bff).into()),
+ ignored: Some(rgba(0x838994ff).into()),
+ ignored_background: Some(rgba(0x3b414dff).into()),
+ ignored_border: Some(rgba(0x464b57ff).into()),
+ info: Some(rgba(0x74ade8ff).into()),
+ info_background: Some(rgba(0x18243dff).into()),
+ info_border: Some(rgba(0x293c5bff).into()),
modified: Some(rgba(0xdec184ff).into()),
- modified_background: Some(rgba(0xfaf2e6ff).into()),
- modified_border: Some(rgba(0xf5e8d2ff).into()),
- predictive: Some(rgba(0x9c9fc7ff).into()),
- predictive_background: Some(rgba(0xe0ebdcff).into()),
- predictive_border: Some(rgba(0xc8dcc1ff).into()),
- renamed: Some(rgba(0x5c79e2ff).into()),
- renamed_background: Some(rgba(0xe2e2faff).into()),
- renamed_border: Some(rgba(0xcbcdf6ff).into()),
- success: Some(rgba(0x669f59ff).into()),
- success_background: Some(rgba(0xe0ebdcff).into()),
- success_border: Some(rgba(0xc8dcc1ff).into()),
- unreachable: Some(rgba(0x7f8188ff).into()),
- unreachable_background: Some(rgba(0xdcdcddff).into()),
- unreachable_border: Some(rgba(0xc9c9caff).into()),
+ modified_background: Some(rgba(0x41331dff).into()),
+ modified_border: Some(rgba(0x5d4c2fff).into()),
+ predictive: Some(rgba(0x5b6b88ff).into()),
+ predictive_background: Some(rgba(0x222e1dff).into()),
+ predictive_border: Some(rgba(0x38482fff).into()),
+ renamed: Some(rgba(0x74ade8ff).into()),
+ renamed_background: Some(rgba(0x18243dff).into()),
+ renamed_border: Some(rgba(0x293c5bff).into()),
+ success: Some(rgba(0xa1c181ff).into()),
+ success_background: Some(rgba(0x222e1dff).into()),
+ success_border: Some(rgba(0x38482fff).into()),
+ unreachable: Some(rgba(0x838994ff).into()),
+ unreachable_background: Some(rgba(0x3b414dff).into()),
+ unreachable_border: Some(rgba(0x464b57ff).into()),
warning: Some(rgba(0xdec184ff).into()),
- warning_background: Some(rgba(0xfaf2e6ff).into()),
- warning_border: Some(rgba(0xf5e8d2ff).into()),
+ warning_background: Some(rgba(0x41331dff).into()),
+ warning_border: Some(rgba(0x5d4c2fff).into()),
..Default::default()
},
player: Some(PlayerColors(vec![
PlayerColor {
- cursor: rgba(0x5c79e2ff).into(),
- background: rgba(0x5c79e2ff).into(),
- selection: rgba(0x5c79e23d).into(),
+ cursor: rgba(0x74ade8ff).into(),
+ background: rgba(0x74ade8ff).into(),
+ selection: rgba(0x74ade83d).into(),
},
PlayerColor {
- cursor: rgba(0x994fa6ff).into(),
- background: rgba(0x994fa6ff).into(),
- selection: rgba(0x994fa63d).into(),
+ cursor: rgba(0xbe5046ff).into(),
+ background: rgba(0xbe5046ff).into(),
+ selection: rgba(0xbe50463d).into(),
},
PlayerColor {
- cursor: rgba(0xad6f27ff).into(),
- background: rgba(0xad6f27ff).into(),
- selection: rgba(0xad6f273d).into(),
+ cursor: rgba(0xc0966bff).into(),
+ background: rgba(0xc0966bff).into(),
+ selection: rgba(0xc0966b3d).into(),
},
PlayerColor {
- cursor: rgba(0xa44aabff).into(),
- background: rgba(0xa44aabff).into(),
- selection: rgba(0xa44aab3d).into(),
+ cursor: rgba(0xb478cfff).into(),
+ background: rgba(0xb478cfff).into(),
+ selection: rgba(0xb478cf3d).into(),
},
PlayerColor {
- cursor: rgba(0x3b82b7ff).into(),
- background: rgba(0x3b82b7ff).into(),
- selection: rgba(0x3b82b73d).into(),
+ cursor: rgba(0x6fb4c0ff).into(),
+ background: rgba(0x6fb4c0ff).into(),
+ selection: rgba(0x6fb4c03d).into(),
},
PlayerColor {
- cursor: rgba(0xd36151ff).into(),
- background: rgba(0xd36151ff).into(),
- selection: rgba(0xd361513d).into(),
+ cursor: rgba(0xd07277ff).into(),
+ background: rgba(0xd07277ff).into(),
+ selection: rgba(0xd072773d).into(),
},
PlayerColor {
cursor: rgba(0xdec184ff).into(),
@@ -177,9 +177,9 @@ pub fn one() -> UserThemeFamily {
selection: rgba(0xdec1843d).into(),
},
PlayerColor {
- cursor: rgba(0x669f59ff).into(),
- background: rgba(0x669f59ff).into(),
- selection: rgba(0x669f593d).into(),
+ cursor: rgba(0xa1c181ff).into(),
+ background: rgba(0xa1c181ff).into(),
+ selection: rgba(0xa1c1813d).into(),
},
])),
syntax: Some(UserSyntaxTheme {
@@ -187,63 +187,63 @@ pub fn one() -> UserThemeFamily {
(
"attribute".into(),
UserHighlightStyle {
- color: Some(rgba(0x5c79e2ff).into()),
+ color: Some(rgba(0x74ade8ff).into()),
..Default::default()
},
),
(
"boolean".into(),
UserHighlightStyle {
- color: Some(rgba(0xad6f26ff).into()),
+ color: Some(rgba(0xc0966bff).into()),
..Default::default()
},
),
(
"comment".into(),
UserHighlightStyle {
- color: Some(rgba(0xa2a3a7ff).into()),
+ color: Some(rgba(0x5d636fff).into()),
..Default::default()
},
),
(
"comment.doc".into(),
UserHighlightStyle {
- color: Some(rgba(0x7c7e86ff).into()),
+ color: Some(rgba(0x878e98ff).into()),
..Default::default()
},
),
(
"constant".into(),
UserHighlightStyle {
- color: Some(rgba(0x669f59ff).into()),
+ color: Some(rgba(0xdfc184ff).into()),
..Default::default()
},
),
(
"constructor".into(),
UserHighlightStyle {
- color: Some(rgba(0x5c79e2ff).into()),
+ color: Some(rgba(0x74ade9ff).into()),
..Default::default()
},
),
(
"embedded".into(),
UserHighlightStyle {
- color: Some(rgba(0x383a41ff).into()),
+ color: Some(rgba(0xc8ccd4ff).into()),
..Default::default()
},
),
(
"emphasis".into(),
UserHighlightStyle {
- color: Some(rgba(0x5c79e2ff).into()),
+ color: Some(rgba(0x74ade8ff).into()),
..Default::default()
},
),
(
"emphasis.strong".into(),
UserHighlightStyle {
- color: Some(rgba(0xad6f26ff).into()),
+ color: Some(rgba(0xc0966bff).into()),
font_weight: Some(UserFontWeight(700.0)),
..Default::default()
},
@@ -251,21 +251,21 @@ pub fn one() -> UserThemeFamily {
(
"enum".into(),
UserHighlightStyle {
- color: Some(rgba(0xd36050ff).into()),
+ color: Some(rgba(0xd07277ff).into()),
..Default::default()
},
),
(
"function".into(),
UserHighlightStyle {
- color: Some(rgba(0x5b79e3ff).into()),
+ color: Some(rgba(0x74ade9ff).into()),
..Default::default()
},
),
(
"hint".into(),
UserHighlightStyle {
- color: Some(rgba(0x9295beff).into()),
+ color: Some(rgba(0x5b708aff).into()),
font_weight: Some(UserFontWeight(700.0)),
..Default::default()
},
@@ -273,50 +273,50 @@ pub fn one() -> UserThemeFamily {
(
"keyword".into(),
UserHighlightStyle {
- color: Some(rgba(0xa449abff).into()),
+ color: Some(rgba(0xb478cfff).into()),
..Default::default()
},
),
(
"label".into(),
UserHighlightStyle {
- color: Some(rgba(0x5c79e2ff).into()),
+ color: Some(rgba(0x74ade8ff).into()),
..Default::default()
},
),
(
"link_text".into(),
UserHighlightStyle {
- color: Some(rgba(0x5b79e3ff).into()),
- font_style: Some(UserFontStyle::Italic),
+ color: Some(rgba(0x74ade9ff).into()),
+ font_style: Some(UserFontStyle::Normal),
..Default::default()
},
),
(
"link_uri".into(),
UserHighlightStyle {
- color: Some(rgba(0x3982b7ff).into()),
+ color: Some(rgba(0x6fb4c0ff).into()),
..Default::default()
},
),
(
"number".into(),
UserHighlightStyle {
- color: Some(rgba(0xad6f26ff).into()),
+ color: Some(rgba(0xc0966bff).into()),
..Default::default()
},
),
(
"operator".into(),
UserHighlightStyle {
- color: Some(rgba(0x3982b7ff).into()),
+ color: Some(rgba(0x6fb4c0ff).into()),
..Default::default()
},
),
(
"predictive".into(),
UserHighlightStyle {
- color: Some(rgba(0x9c9fc7ff).into()),
+ color: Some(rgba(0x5b6b88ff).into()),
font_style: Some(UserFontStyle::Italic),
..Default::default()
},
@@ -324,112 +324,112 @@ pub fn one() -> UserThemeFamily {
(
"preproc".into(),
UserHighlightStyle {
- color: Some(rgba(0x383a41ff).into()),
+ color: Some(rgba(0xc8ccd4ff).into()),
..Default::default()
},
),
(
"primary".into(),
UserHighlightStyle {
- color: Some(rgba(0x383a41ff).into()),
+ color: Some(rgba(0xacb2beff).into()),
..Default::default()
},
),
(
"property".into(),
UserHighlightStyle {
- color: Some(rgba(0xd36050ff).into()),
+ color: Some(rgba(0xd07277ff).into()),
..Default::default()
},
),
(
"punctuation".into(),
UserHighlightStyle {
- color: Some(rgba(0x383a41ff).into()),
+ color: Some(rgba(0xacb2beff).into()),
..Default::default()
},
),
(
"punctuation.bracket".into(),
UserHighlightStyle {
- color: Some(rgba(0x4d4f52ff).into()),
+ color: Some(rgba(0xb2b9c6ff).into()),
..Default::default()
},
),
(
"punctuation.delimiter".into(),
UserHighlightStyle {
- color: Some(rgba(0x4d4f52ff).into()),
+ color: Some(rgba(0xb2b9c6ff).into()),
..Default::default()
},
),
(
"punctuation.list_marker".into(),
UserHighlightStyle {
- color: Some(rgba(0xd36050ff).into()),
+ color: Some(rgba(0xd07277ff).into()),
..Default::default()
},
),
(
"punctuation.special".into(),
UserHighlightStyle {
- color: Some(rgba(0xb92c46ff).into()),
+ color: Some(rgba(0xb1574bff).into()),
..Default::default()
},
),
(
"string".into(),
UserHighlightStyle {
- color: Some(rgba(0x659f58ff).into()),
+ color: Some(rgba(0xa1c181ff).into()),
..Default::default()
},
),
(
"string.escape".into(),
UserHighlightStyle {
- color: Some(rgba(0x7c7e86ff).into()),
+ color: Some(rgba(0x878e98ff).into()),
..Default::default()
},
),
(
"string.regex".into(),
UserHighlightStyle {
- color: Some(rgba(0xad6f27ff).into()),
+ color: Some(rgba(0xc0966bff).into()),
..Default::default()
},
),
(
"string.special".into(),
UserHighlightStyle {
- color: Some(rgba(0xad6f27ff).into()),
+ color: Some(rgba(0xc0966bff).into()),
..Default::default()
},
),
(
"string.special.symbol".into(),
UserHighlightStyle {
- color: Some(rgba(0xad6f27ff).into()),
+ color: Some(rgba(0xc0966bff).into()),
..Default::default()
},
),
(
"tag".into(),
UserHighlightStyle {
- color: Some(rgba(0x5c79e2ff).into()),
+ color: Some(rgba(0x74ade8ff).into()),
..Default::default()
},
),
(
"text.literal".into(),
UserHighlightStyle {
- color: Some(rgba(0x659f58ff).into()),
+ color: Some(rgba(0xa1c181ff).into()),
..Default::default()
},
),
(
"title".into(),
UserHighlightStyle {
- color: Some(rgba(0xd36050ff).into()),
+ color: Some(rgba(0xd07277ff).into()),
font_weight: Some(UserFontWeight(400.0)),
..Default::default()
},
@@ -437,28 +437,28 @@ pub fn one() -> UserThemeFamily {
(
"type".into(),
UserHighlightStyle {
- color: Some(rgba(0x3982b7ff).into()),
+ color: Some(rgba(0x6fb4c0ff).into()),
..Default::default()
},
),
(
"variable".into(),
UserHighlightStyle {
- color: Some(rgba(0x383a41ff).into()),
+ color: Some(rgba(0xc8ccd4ff).into()),
..Default::default()
},
),
(
"variable.special".into(),
UserHighlightStyle {
- color: Some(rgba(0xad6f26ff).into()),
+ color: Some(rgba(0xc0966bff).into()),
..Default::default()
},
),
(
"variant".into(),
UserHighlightStyle {
- color: Some(rgba(0x5b79e3ff).into()),
+ color: Some(rgba(0x74ade9ff).into()),
..Default::default()
},
),
@@ -467,160 +467,160 @@ pub fn one() -> UserThemeFamily {
},
},
UserTheme {
- name: "One Dark".into(),
- appearance: Appearance::Dark,
+ name: "One Light".into(),
+ appearance: Appearance::Light,
styles: UserThemeStylesRefinement {
colors: ThemeColorsRefinement {
- border: Some(rgba(0x464b57ff).into()),
- border_variant: Some(rgba(0x363c46ff).into()),
- border_focused: Some(rgba(0x293c5bff).into()),
- border_selected: Some(rgba(0x293c5bff).into()),
+ border: Some(rgba(0xc9c9caff).into()),
+ border_variant: Some(rgba(0xdfdfe0ff).into()),
+ border_focused: Some(rgba(0xcbcdf6ff).into()),
+ border_selected: Some(rgba(0xcbcdf6ff).into()),
border_transparent: Some(rgba(0x00000000).into()),
- border_disabled: Some(rgba(0x414754ff).into()),
- elevated_surface_background: Some(rgba(0x2f343eff).into()),
- surface_background: Some(rgba(0x2f343eff).into()),
- background: Some(rgba(0x3b414dff).into()),
- panel_background: Some(rgba(0x2f343eff).into()),
- element_background: Some(rgba(0x2f343eff).into()),
- element_hover: Some(rgba(0x363c46ff).into()),
- element_active: Some(rgba(0x454a56ff).into()),
- element_selected: Some(rgba(0x454a56ff).into()),
- element_disabled: Some(rgba(0x2f343eff).into()),
- drop_target_background: Some(rgba(0x83899480).into()),
+ border_disabled: Some(rgba(0xd3d3d4ff).into()),
+ elevated_surface_background: Some(rgba(0xebebecff).into()),
+ surface_background: Some(rgba(0xebebecff).into()),
+ background: Some(rgba(0xdcdcddff).into()),
+ panel_background: Some(rgba(0xebebecff).into()),
+ element_background: Some(rgba(0xebebecff).into()),
+ element_hover: Some(rgba(0xdfdfe0ff).into()),
+ element_active: Some(rgba(0xcacacaff).into()),
+ element_selected: Some(rgba(0xcacacaff).into()),
+ element_disabled: Some(rgba(0xebebecff).into()),
+ drop_target_background: Some(rgba(0x7f818880).into()),
ghost_element_background: Some(rgba(0x00000000).into()),
- ghost_element_hover: Some(rgba(0x363c46ff).into()),
- ghost_element_active: Some(rgba(0x454a56ff).into()),
- ghost_element_selected: Some(rgba(0x454a56ff).into()),
- ghost_element_disabled: Some(rgba(0x2f343eff).into()),
- text: Some(rgba(0xc8ccd4ff).into()),
- text_muted: Some(rgba(0x838994ff).into()),
- text_placeholder: Some(rgba(0x555a63ff).into()),
- text_disabled: Some(rgba(0x555a63ff).into()),
- text_accent: Some(rgba(0x74ade8ff).into()),
- icon: Some(rgba(0xc8ccd4ff).into()),
- icon_muted: Some(rgba(0x838994ff).into()),
- icon_disabled: Some(rgba(0x555a63ff).into()),
- icon_placeholder: Some(rgba(0x838994ff).into()),
- icon_accent: Some(rgba(0x74ade8ff).into()),
- status_bar_background: Some(rgba(0x3b414dff).into()),
- title_bar_background: Some(rgba(0x3b414dff).into()),
- toolbar_background: Some(rgba(0x282c34ff).into()),
- tab_bar_background: Some(rgba(0x2f343eff).into()),
- tab_inactive_background: Some(rgba(0x2f343eff).into()),
- tab_active_background: Some(rgba(0x282c34ff).into()),
- scrollbar_thumb_background: Some(rgba(0xc8ccd44c).into()),
- scrollbar_thumb_hover_background: Some(rgba(0x363c46ff).into()),
- scrollbar_thumb_border: Some(rgba(0x363c46ff).into()),
- scrollbar_track_background: Some(rgba(0x00000000).into()),
- scrollbar_track_border: Some(rgba(0x2e333cff).into()),
- editor_foreground: Some(rgba(0xacb2beff).into()),
- editor_background: Some(rgba(0x282c34ff).into()),
- editor_gutter_background: Some(rgba(0x282c34ff).into()),
- editor_subheader_background: Some(rgba(0x2f343eff).into()),
- editor_active_line_background: Some(rgba(0x2f343ebf).into()),
- editor_highlighted_line_background: Some(rgba(0x2f343eff).into()),
- editor_line_number: Some(rgba(0xc8ccd459).into()),
- editor_active_line_number: Some(rgba(0xc8ccd4ff).into()),
- editor_invisible: Some(rgba(0x838994ff).into()),
- editor_wrap_guide: Some(rgba(0xc8ccd40d).into()),
- editor_active_wrap_guide: Some(rgba(0xc8ccd41a).into()),
- editor_document_highlight_read_background: Some(rgba(0x74ade81a).into()),
- editor_document_highlight_write_background: Some(rgba(0x555a6366).into()),
- terminal_background: Some(rgba(0x282c34ff).into()),
- terminal_ansi_bright_black: Some(rgba(0x525661ff).into()),
- terminal_ansi_bright_red: Some(rgba(0x673a3cff).into()),
- terminal_ansi_bright_green: Some(rgba(0x4d6140ff).into()),
- terminal_ansi_bright_yellow: Some(rgba(0x786441ff).into()),
- terminal_ansi_bright_blue: Some(rgba(0x385378ff).into()),
- terminal_ansi_bright_magenta: Some(rgba(0x5e2b26ff).into()),
- terminal_ansi_bright_cyan: Some(rgba(0x3a565bff).into()),
- terminal_ansi_bright_white: Some(rgba(0xc8ccd4ff).into()),
- terminal_ansi_black: Some(rgba(0x282c34ff).into()),
- terminal_ansi_red: Some(rgba(0xd07277ff).into()),
- terminal_ansi_green: Some(rgba(0xa1c181ff).into()),
+ ghost_element_hover: Some(rgba(0xdfdfe0ff).into()),
+ ghost_element_active: Some(rgba(0xcacacaff).into()),
+ ghost_element_selected: Some(rgba(0xcacacaff).into()),
+ ghost_element_disabled: Some(rgba(0xebebecff).into()),
+ text: Some(rgba(0x383a41ff).into()),
+ text_muted: Some(rgba(0x7f8188ff).into()),
+ text_placeholder: Some(rgba(0xa1a1a3ff).into()),
+ text_disabled: Some(rgba(0xa1a1a3ff).into()),
+ text_accent: Some(rgba(0x5c79e2ff).into()),
+ icon: Some(rgba(0x383a41ff).into()),
+ icon_muted: Some(rgba(0x7f8188ff).into()),
+ icon_disabled: Some(rgba(0xa1a1a3ff).into()),
+ icon_placeholder: Some(rgba(0x7f8188ff).into()),
+ icon_accent: Some(rgba(0x5c79e2ff).into()),
+ status_bar_background: Some(rgba(0xdcdcddff).into()),
+ title_bar_background: Some(rgba(0xdcdcddff).into()),
+ toolbar_background: Some(rgba(0xfafafaff).into()),
+ tab_bar_background: Some(rgba(0xebebecff).into()),
+ tab_inactive_background: Some(rgba(0xebebecff).into()),
+ tab_active_background: Some(rgba(0xfafafaff).into()),
+ scrollbar_thumb_background: Some(rgba(0x383a414c).into()),
+ scrollbar_thumb_hover_background: Some(rgba(0xdfdfe0ff).into()),
+ scrollbar_thumb_border: Some(rgba(0xdfdfe0ff).into()),
+ scrollbar_track_background: Some(rgba(0x00000000).into()),
+ scrollbar_track_border: Some(rgba(0xeeeeeeff).into()),
+ editor_foreground: Some(rgba(0x383a41ff).into()),
+ editor_background: Some(rgba(0xfafafaff).into()),
+ editor_gutter_background: Some(rgba(0xfafafaff).into()),
+ editor_subheader_background: Some(rgba(0xebebecff).into()),
+ editor_active_line_background: Some(rgba(0xebebecbf).into()),
+ editor_highlighted_line_background: Some(rgba(0xebebecff).into()),
+ editor_line_number: Some(rgba(0x383a4159).into()),
+ editor_active_line_number: Some(rgba(0x383a41ff).into()),
+ editor_invisible: Some(rgba(0x7f8188ff).into()),
+ editor_wrap_guide: Some(rgba(0x383a410d).into()),
+ editor_active_wrap_guide: Some(rgba(0x383a411a).into()),
+ editor_document_highlight_read_background: Some(rgba(0x5c79e21a).into()),
+ editor_document_highlight_write_background: Some(rgba(0xa3a3a466).into()),
+ terminal_background: Some(rgba(0xfafafaff).into()),
+ terminal_ansi_bright_black: Some(rgba(0xaaaaaaff).into()),
+ terminal_ansi_bright_red: Some(rgba(0xf0b0a4ff).into()),
+ terminal_ansi_bright_green: Some(rgba(0xb2cfa9ff).into()),
+ terminal_ansi_bright_yellow: Some(rgba(0xf1dfc1ff).into()),
+ terminal_ansi_bright_blue: Some(rgba(0xb5baf2ff).into()),
+ terminal_ansi_bright_magenta: Some(rgba(0xcea6d3ff).into()),
+ terminal_ansi_bright_cyan: Some(rgba(0xa4bfdbff).into()),
+ terminal_ansi_bright_white: Some(rgba(0x383a41ff).into()),
+ terminal_ansi_black: Some(rgba(0xfafafaff).into()),
+ terminal_ansi_red: Some(rgba(0xd36151ff).into()),
+ terminal_ansi_green: Some(rgba(0x669f59ff).into()),
terminal_ansi_yellow: Some(rgba(0xdec184ff).into()),
- terminal_ansi_blue: Some(rgba(0x74ade8ff).into()),
- terminal_ansi_magenta: Some(rgba(0xbe5046ff).into()),
- terminal_ansi_cyan: Some(rgba(0x6fb4c0ff).into()),
- terminal_ansi_white: Some(rgba(0xc8ccd4ff).into()),
- link_text_hover: Some(rgba(0x74ade8ff).into()),
+ terminal_ansi_blue: Some(rgba(0x5c79e2ff).into()),
+ terminal_ansi_magenta: Some(rgba(0x994fa6ff).into()),
+ terminal_ansi_cyan: Some(rgba(0x3b82b7ff).into()),
+ terminal_ansi_white: Some(rgba(0x383a41ff).into()),
+ link_text_hover: Some(rgba(0x5c79e2ff).into()),
..Default::default()
},
status: StatusColorsRefinement {
conflict: Some(rgba(0xdec184ff).into()),
- conflict_background: Some(rgba(0x41331dff).into()),
- conflict_border: Some(rgba(0x5d4c2fff).into()),
- created: Some(rgba(0xa1c181ff).into()),
- created_background: Some(rgba(0x222e1dff).into()),
- created_border: Some(rgba(0x38482fff).into()),
- deleted: Some(rgba(0xd07277ff).into()),
- deleted_background: Some(rgba(0x301b1cff).into()),
- deleted_border: Some(rgba(0x4c2b2cff).into()),
- error: Some(rgba(0xd07277ff).into()),
- error_background: Some(rgba(0x301b1cff).into()),
- error_border: Some(rgba(0x4c2b2cff).into()),
- hidden: Some(rgba(0x555a63ff).into()),
- hidden_background: Some(rgba(0x3b414dff).into()),
- hidden_border: Some(rgba(0x414754ff).into()),
- hint: Some(rgba(0x5b708aff).into()),
- hint_background: Some(rgba(0x18243dff).into()),
- hint_border: Some(rgba(0x293c5bff).into()),
- ignored: Some(rgba(0x838994ff).into()),
- ignored_background: Some(rgba(0x3b414dff).into()),
- ignored_border: Some(rgba(0x464b57ff).into()),
- info: Some(rgba(0x74ade8ff).into()),
- info_background: Some(rgba(0x18243dff).into()),
- info_border: Some(rgba(0x293c5bff).into()),
+ conflict_background: Some(rgba(0xfaf2e6ff).into()),
+ conflict_border: Some(rgba(0xf5e8d2ff).into()),
+ created: Some(rgba(0x669f59ff).into()),
+ created_background: Some(rgba(0xe0ebdcff).into()),
+ created_border: Some(rgba(0xc8dcc1ff).into()),
+ deleted: Some(rgba(0xd36151ff).into()),
+ deleted_background: Some(rgba(0xfbdfd9ff).into()),
+ deleted_border: Some(rgba(0xf6c6bdff).into()),
+ error: Some(rgba(0xd36151ff).into()),
+ error_background: Some(rgba(0xfbdfd9ff).into()),
+ error_border: Some(rgba(0xf6c6bdff).into()),
+ hidden: Some(rgba(0xa1a1a3ff).into()),
+ hidden_background: Some(rgba(0xdcdcddff).into()),
+ hidden_border: Some(rgba(0xd3d3d4ff).into()),
+ hint: Some(rgba(0x9295beff).into()),
+ hint_background: Some(rgba(0xe2e2faff).into()),
+ hint_border: Some(rgba(0xcbcdf6ff).into()),
+ ignored: Some(rgba(0x7f8188ff).into()),
+ ignored_background: Some(rgba(0xdcdcddff).into()),
+ ignored_border: Some(rgba(0xc9c9caff).into()),
+ info: Some(rgba(0x5c79e2ff).into()),
+ info_background: Some(rgba(0xe2e2faff).into()),
+ info_border: Some(rgba(0xcbcdf6ff).into()),
modified: Some(rgba(0xdec184ff).into()),
- modified_background: Some(rgba(0x41331dff).into()),
- modified_border: Some(rgba(0x5d4c2fff).into()),
- predictive: Some(rgba(0x5b6b88ff).into()),
- predictive_background: Some(rgba(0x222e1dff).into()),
- predictive_border: Some(rgba(0x38482fff).into()),
- renamed: Some(rgba(0x74ade8ff).into()),
- renamed_background: Some(rgba(0x18243dff).into()),
- renamed_border: Some(rgba(0x293c5bff).into()),
- success: Some(rgba(0xa1c181ff).into()),
- success_background: Some(rgba(0x222e1dff).into()),
- success_border: Some(rgba(0x38482fff).into()),
- unreachable: Some(rgba(0x838994ff).into()),
- unreachable_background: Some(rgba(0x3b414dff).into()),
- unreachable_border: Some(rgba(0x464b57ff).into()),
+ modified_background: Some(rgba(0xfaf2e6ff).into()),
+ modified_border: Some(rgba(0xf5e8d2ff).into()),
+ predictive: Some(rgba(0x9c9fc7ff).into()),
+ predictive_background: Some(rgba(0xe0ebdcff).into()),
+ predictive_border: Some(rgba(0xc8dcc1ff).into()),
+ renamed: Some(rgba(0x5c79e2ff).into()),
+ renamed_background: Some(rgba(0xe2e2faff).into()),
+ renamed_border: Some(rgba(0xcbcdf6ff).into()),
+ success: Some(rgba(0x669f59ff).into()),
+ success_background: Some(rgba(0xe0ebdcff).into()),
+ success_border: Some(rgba(0xc8dcc1ff).into()),
+ unreachable: Some(rgba(0x7f8188ff).into()),
+ unreachable_background: Some(rgba(0xdcdcddff).into()),
+ unreachable_border: Some(rgba(0xc9c9caff).into()),
warning: Some(rgba(0xdec184ff).into()),
- warning_background: Some(rgba(0x41331dff).into()),
- warning_border: Some(rgba(0x5d4c2fff).into()),
+ warning_background: Some(rgba(0xfaf2e6ff).into()),
+ warning_border: Some(rgba(0xf5e8d2ff).into()),
..Default::default()
},
player: Some(PlayerColors(vec![
PlayerColor {
- cursor: rgba(0x74ade8ff).into(),
- background: rgba(0x74ade8ff).into(),
- selection: rgba(0x74ade83d).into(),
+ cursor: rgba(0x5c79e2ff).into(),
+ background: rgba(0x5c79e2ff).into(),
+ selection: rgba(0x5c79e23d).into(),
},
PlayerColor {
- cursor: rgba(0xbe5046ff).into(),
- background: rgba(0xbe5046ff).into(),
- selection: rgba(0xbe50463d).into(),
+ cursor: rgba(0x994fa6ff).into(),
+ background: rgba(0x994fa6ff).into(),
+ selection: rgba(0x994fa63d).into(),
},
PlayerColor {
- cursor: rgba(0xc0966bff).into(),
- background: rgba(0xc0966bff).into(),
- selection: rgba(0xc0966b3d).into(),
+ cursor: rgba(0xad6f27ff).into(),
+ background: rgba(0xad6f27ff).into(),
+ selection: rgba(0xad6f273d).into(),
},
PlayerColor {
- cursor: rgba(0xb478cfff).into(),
- background: rgba(0xb478cfff).into(),
- selection: rgba(0xb478cf3d).into(),
+ cursor: rgba(0xa44aabff).into(),
+ background: rgba(0xa44aabff).into(),
+ selection: rgba(0xa44aab3d).into(),
},
PlayerColor {
- cursor: rgba(0x6fb4c0ff).into(),
- background: rgba(0x6fb4c0ff).into(),
- selection: rgba(0x6fb4c03d).into(),
+ cursor: rgba(0x3b82b7ff).into(),
+ background: rgba(0x3b82b7ff).into(),
+ selection: rgba(0x3b82b73d).into(),
},
PlayerColor {
- cursor: rgba(0xd07277ff).into(),
- background: rgba(0xd07277ff).into(),
- selection: rgba(0xd072773d).into(),
+ cursor: rgba(0xd36151ff).into(),
+ background: rgba(0xd36151ff).into(),
+ selection: rgba(0xd361513d).into(),
},
PlayerColor {
cursor: rgba(0xdec184ff).into(),
@@ -628,9 +628,9 @@ pub fn one() -> UserThemeFamily {
selection: rgba(0xdec1843d).into(),
},
PlayerColor {
- cursor: rgba(0xa1c181ff).into(),
- background: rgba(0xa1c181ff).into(),
- selection: rgba(0xa1c1813d).into(),
+ cursor: rgba(0x669f59ff).into(),
+ background: rgba(0x669f59ff).into(),
+ selection: rgba(0x669f593d).into(),
},
])),
syntax: Some(UserSyntaxTheme {
@@ -638,63 +638,63 @@ pub fn one() -> UserThemeFamily {
(
"attribute".into(),
UserHighlightStyle {
- color: Some(rgba(0x74ade8ff).into()),
+ color: Some(rgba(0x5c79e2ff).into()),
..Default::default()
},
),
(
"boolean".into(),
UserHighlightStyle {
- color: Some(rgba(0xc0966bff).into()),
+ color: Some(rgba(0xad6f26ff).into()),
..Default::default()
},
),
(
"comment".into(),
UserHighlightStyle {
- color: Some(rgba(0x5d636fff).into()),
+ color: Some(rgba(0xa2a3a7ff).into()),
..Default::default()
},
),
(
"comment.doc".into(),
UserHighlightStyle {
- color: Some(rgba(0x878e98ff).into()),
+ color: Some(rgba(0x7c7e86ff).into()),
..Default::default()
},
),
(
"constant".into(),
UserHighlightStyle {
- color: Some(rgba(0xdfc184ff).into()),
+ color: Some(rgba(0x669f59ff).into()),
..Default::default()
},
),
(
"constructor".into(),
UserHighlightStyle {
- color: Some(rgba(0x74ade9ff).into()),
+ color: Some(rgba(0x5c79e2ff).into()),
..Default::default()
},
),
(
"embedded".into(),
UserHighlightStyle {
- color: Some(rgba(0xc8ccd4ff).into()),
+ color: Some(rgba(0x383a41ff).into()),
..Default::default()
},
),
(
"emphasis".into(),
UserHighlightStyle {
- color: Some(rgba(0x74ade8ff).into()),
+ color: Some(rgba(0x5c79e2ff).into()),
..Default::default()
},
),
(
"emphasis.strong".into(),
UserHighlightStyle {
- color: Some(rgba(0xc0966bff).into()),
+ color: Some(rgba(0xad6f26ff).into()),
font_weight: Some(UserFontWeight(700.0)),
..Default::default()
},
@@ -702,21 +702,21 @@ pub fn one() -> UserThemeFamily {
(
"enum".into(),
UserHighlightStyle {
- color: Some(rgba(0xd07277ff).into()),
+ color: Some(rgba(0xd36050ff).into()),
..Default::default()
},
),
(
"function".into(),
UserHighlightStyle {
- color: Some(rgba(0x74ade9ff).into()),
+ color: Some(rgba(0x5b79e3ff).into()),
..Default::default()
},
),
(
"hint".into(),
UserHighlightStyle {
- color: Some(rgba(0x5b708aff).into()),
+ color: Some(rgba(0x9295beff).into()),
font_weight: Some(UserFontWeight(700.0)),
..Default::default()
},
@@ -16,170 +16,170 @@ pub fn rose_pine() -> UserThemeFamily {
author: "Zed Industries".into(),
themes: vec![
UserTheme {
- name: "Rosé Pine Dawn".into(),
- appearance: Appearance::Light,
+ name: "Rosé Pine".into(),
+ appearance: Appearance::Dark,
styles: UserThemeStylesRefinement {
colors: ThemeColorsRefinement {
- border: Some(rgba(0xdcd6d5ff).into()),
- border_variant: Some(rgba(0xe5e0dfff).into()),
- border_focused: Some(rgba(0xc3d7dbff).into()),
- border_selected: Some(rgba(0xc3d7dbff).into()),
+ border: Some(rgba(0x423f55ff).into()),
+ border_variant: Some(rgba(0x232132ff).into()),
+ border_focused: Some(rgba(0x435255ff).into()),
+ border_selected: Some(rgba(0x435255ff).into()),
border_transparent: Some(rgba(0x00000000).into()),
- border_disabled: Some(rgba(0xd0cccfff).into()),
- elevated_surface_background: Some(rgba(0xfef9f2ff).into()),
- surface_background: Some(rgba(0xfef9f2ff).into()),
- background: Some(rgba(0xdcd8d8ff).into()),
- panel_background: Some(rgba(0xfef9f2ff).into()),
- element_background: Some(rgba(0xfef9f2ff).into()),
- element_hover: Some(rgba(0xe5e0dfff).into()),
- element_active: Some(rgba(0xdbd5d4ff).into()),
- element_selected: Some(rgba(0xdbd5d4ff).into()),
- element_disabled: Some(rgba(0xfef9f2ff).into()),
- drop_target_background: Some(rgba(0x706c8c80).into()),
+ border_disabled: Some(rgba(0x353347ff).into()),
+ elevated_surface_background: Some(rgba(0x1d1b2aff).into()),
+ surface_background: Some(rgba(0x1d1b2aff).into()),
+ background: Some(rgba(0x292739ff).into()),
+ panel_background: Some(rgba(0x1d1b2aff).into()),
+ element_background: Some(rgba(0x1d1b2aff).into()),
+ element_hover: Some(rgba(0x232132ff).into()),
+ element_active: Some(rgba(0x403e53ff).into()),
+ element_selected: Some(rgba(0x403e53ff).into()),
+ element_disabled: Some(rgba(0x1d1b2aff).into()),
+ drop_target_background: Some(rgba(0x75718e80).into()),
ghost_element_background: Some(rgba(0x00000000).into()),
- ghost_element_hover: Some(rgba(0xe5e0dfff).into()),
- ghost_element_active: Some(rgba(0xdbd5d4ff).into()),
- ghost_element_selected: Some(rgba(0xdbd5d4ff).into()),
- ghost_element_disabled: Some(rgba(0xfef9f2ff).into()),
- text: Some(rgba(0x575279ff).into()),
- text_muted: Some(rgba(0x706c8cff).into()),
- text_placeholder: Some(rgba(0x938fa3ff).into()),
- text_disabled: Some(rgba(0x938fa3ff).into()),
- text_accent: Some(rgba(0x57949fff).into()),
- icon: Some(rgba(0x575279ff).into()),
- icon_muted: Some(rgba(0x706c8cff).into()),
- icon_disabled: Some(rgba(0x938fa3ff).into()),
- icon_placeholder: Some(rgba(0x706c8cff).into()),
- icon_accent: Some(rgba(0x57949fff).into()),
- status_bar_background: Some(rgba(0xdcd8d8ff).into()),
- title_bar_background: Some(rgba(0xdcd8d8ff).into()),
- toolbar_background: Some(rgba(0xfaf4edff).into()),
- tab_bar_background: Some(rgba(0xfef9f2ff).into()),
- tab_inactive_background: Some(rgba(0xfef9f2ff).into()),
- tab_active_background: Some(rgba(0xfaf4edff).into()),
- scrollbar_thumb_background: Some(rgba(0x5752794c).into()),
- scrollbar_thumb_hover_background: Some(rgba(0xe5e0dfff).into()),
- scrollbar_thumb_border: Some(rgba(0xe5e0dfff).into()),
+ ghost_element_hover: Some(rgba(0x232132ff).into()),
+ ghost_element_active: Some(rgba(0x403e53ff).into()),
+ ghost_element_selected: Some(rgba(0x403e53ff).into()),
+ ghost_element_disabled: Some(rgba(0x1d1b2aff).into()),
+ text: Some(rgba(0xe0def4ff).into()),
+ text_muted: Some(rgba(0x75718eff).into()),
+ text_placeholder: Some(rgba(0x2f2b43ff).into()),
+ text_disabled: Some(rgba(0x2f2b43ff).into()),
+ text_accent: Some(rgba(0x9cced7ff).into()),
+ icon: Some(rgba(0xe0def4ff).into()),
+ icon_muted: Some(rgba(0x75718eff).into()),
+ icon_disabled: Some(rgba(0x2f2b43ff).into()),
+ icon_placeholder: Some(rgba(0x75718eff).into()),
+ icon_accent: Some(rgba(0x9cced7ff).into()),
+ status_bar_background: Some(rgba(0x292739ff).into()),
+ title_bar_background: Some(rgba(0x292739ff).into()),
+ toolbar_background: Some(rgba(0x191724ff).into()),
+ tab_bar_background: Some(rgba(0x1d1b2aff).into()),
+ tab_inactive_background: Some(rgba(0x1d1b2aff).into()),
+ tab_active_background: Some(rgba(0x191724ff).into()),
+ scrollbar_thumb_background: Some(rgba(0xe0def44c).into()),
+ scrollbar_thumb_hover_background: Some(rgba(0x232132ff).into()),
+ scrollbar_thumb_border: Some(rgba(0x232132ff).into()),
scrollbar_track_background: Some(rgba(0x00000000).into()),
- scrollbar_track_border: Some(rgba(0xfdf8f1ff).into()),
- editor_foreground: Some(rgba(0x575279ff).into()),
- editor_background: Some(rgba(0xfaf4edff).into()),
- editor_gutter_background: Some(rgba(0xfaf4edff).into()),
- editor_subheader_background: Some(rgba(0xfef9f2ff).into()),
- editor_active_line_background: Some(rgba(0xfef9f2bf).into()),
- editor_highlighted_line_background: Some(rgba(0xfef9f2ff).into()),
- editor_line_number: Some(rgba(0x57527959).into()),
- editor_active_line_number: Some(rgba(0x575279ff).into()),
- editor_invisible: Some(rgba(0x706c8cff).into()),
- editor_wrap_guide: Some(rgba(0x5752790d).into()),
- editor_active_wrap_guide: Some(rgba(0x5752791a).into()),
- editor_document_highlight_read_background: Some(rgba(0x57949f1a).into()),
- editor_document_highlight_write_background: Some(rgba(0x9691a466).into()),
- terminal_background: Some(rgba(0xfaf4edff).into()),
- terminal_ansi_bright_black: Some(rgba(0xb8b2baff).into()),
- terminal_ansi_bright_red: Some(rgba(0xdcb0bbff).into()),
- terminal_ansi_bright_green: Some(rgba(0xa5d5c5ff).into()),
- terminal_ansi_bright_yellow: Some(rgba(0xfccd9bff).into()),
- terminal_ansi_bright_blue: Some(rgba(0xacc9ceff).into()),
- terminal_ansi_bright_magenta: Some(rgba(0xbcb1bdff).into()),
- terminal_ansi_bright_cyan: Some(rgba(0x97b1c0ff).into()),
- terminal_ansi_bright_white: Some(rgba(0x575279ff).into()),
- terminal_ansi_black: Some(rgba(0xfaf4edff).into()),
- terminal_ansi_red: Some(rgba(0xb4647aff).into()),
- terminal_ansi_green: Some(rgba(0x3eaa8eff).into()),
- terminal_ansi_yellow: Some(rgba(0xe99d35ff).into()),
- terminal_ansi_blue: Some(rgba(0x57949fff).into()),
- terminal_ansi_magenta: Some(rgba(0x7c697fff).into()),
- terminal_ansi_cyan: Some(rgba(0x2a6983ff).into()),
- terminal_ansi_white: Some(rgba(0x575279ff).into()),
- link_text_hover: Some(rgba(0x57949fff).into()),
+ scrollbar_track_border: Some(rgba(0x1c1a29ff).into()),
+ editor_foreground: Some(rgba(0xe0def4ff).into()),
+ editor_background: Some(rgba(0x191724ff).into()),
+ editor_gutter_background: Some(rgba(0x191724ff).into()),
+ editor_subheader_background: Some(rgba(0x1d1b2aff).into()),
+ editor_active_line_background: Some(rgba(0x1d1b2abf).into()),
+ editor_highlighted_line_background: Some(rgba(0x1d1b2aff).into()),
+ editor_line_number: Some(rgba(0xe0def459).into()),
+ editor_active_line_number: Some(rgba(0xe0def4ff).into()),
+ editor_invisible: Some(rgba(0x75718eff).into()),
+ editor_wrap_guide: Some(rgba(0xe0def40d).into()),
+ editor_active_wrap_guide: Some(rgba(0xe0def41a).into()),
+ editor_document_highlight_read_background: Some(rgba(0x9cced71a).into()),
+ editor_document_highlight_write_background: Some(rgba(0x28253c66).into()),
+ terminal_background: Some(rgba(0x191724ff).into()),
+ terminal_ansi_bright_black: Some(rgba(0x403d55ff).into()),
+ terminal_ansi_bright_red: Some(rgba(0x7e3647ff).into()),
+ terminal_ansi_bright_green: Some(rgba(0x31614fff).into()),
+ terminal_ansi_bright_yellow: Some(rgba(0x8a653bff).into()),
+ terminal_ansi_bright_blue: Some(rgba(0x566c70ff).into()),
+ terminal_ansi_bright_magenta: Some(rgba(0x4c3b47ff).into()),
+ terminal_ansi_bright_cyan: Some(rgba(0x203a46ff).into()),
+ terminal_ansi_bright_white: Some(rgba(0xe0def4ff).into()),
+ terminal_ansi_black: Some(rgba(0x191724ff).into()),
+ terminal_ansi_red: Some(rgba(0xea6f92ff).into()),
+ terminal_ansi_green: Some(rgba(0x5dc2a3ff).into()),
+ terminal_ansi_yellow: Some(rgba(0xf5c177ff).into()),
+ terminal_ansi_blue: Some(rgba(0x9cced7ff).into()),
+ terminal_ansi_magenta: Some(rgba(0x9d7691ff).into()),
+ terminal_ansi_cyan: Some(rgba(0x32748fff).into()),
+ terminal_ansi_white: Some(rgba(0xe0def4ff).into()),
+ link_text_hover: Some(rgba(0x9cced7ff).into()),
..Default::default()
},
status: StatusColorsRefinement {
- conflict: Some(rgba(0xe99d35ff).into()),
- conflict_background: Some(rgba(0xffebd6ff).into()),
- conflict_border: Some(rgba(0xffdab7ff).into()),
- created: Some(rgba(0x3eaa8eff).into()),
- created_background: Some(rgba(0xdbeee7ff).into()),
- created_border: Some(rgba(0xbee0d5ff).into()),
- deleted: Some(rgba(0xb4647aff).into()),
- deleted_background: Some(rgba(0xf1dfe3ff).into()),
- deleted_border: Some(rgba(0xe6c6cdff).into()),
- error: Some(rgba(0xb4647aff).into()),
- error_background: Some(rgba(0xf1dfe3ff).into()),
- error_border: Some(rgba(0xe6c6cdff).into()),
- hidden: Some(rgba(0x938fa3ff).into()),
- hidden_background: Some(rgba(0xdcd8d8ff).into()),
- hidden_border: Some(rgba(0xd0cccfff).into()),
- hint: Some(rgba(0x7a92aaff).into()),
- hint_background: Some(rgba(0xdde9ebff).into()),
- hint_border: Some(rgba(0xc3d7dbff).into()),
- ignored: Some(rgba(0x706c8cff).into()),
- ignored_background: Some(rgba(0xdcd8d8ff).into()),
- ignored_border: Some(rgba(0xdcd6d5ff).into()),
- info: Some(rgba(0x57949fff).into()),
- info_background: Some(rgba(0xdde9ebff).into()),
- info_border: Some(rgba(0xc3d7dbff).into()),
- modified: Some(rgba(0xe99d35ff).into()),
- modified_background: Some(rgba(0xffebd6ff).into()),
- modified_border: Some(rgba(0xffdab7ff).into()),
- predictive: Some(rgba(0xa2acbeff).into()),
- predictive_background: Some(rgba(0xdbeee7ff).into()),
- predictive_border: Some(rgba(0xbee0d5ff).into()),
- renamed: Some(rgba(0x57949fff).into()),
- renamed_background: Some(rgba(0xdde9ebff).into()),
- renamed_border: Some(rgba(0xc3d7dbff).into()),
- success: Some(rgba(0x3eaa8eff).into()),
- success_background: Some(rgba(0xdbeee7ff).into()),
- success_border: Some(rgba(0xbee0d5ff).into()),
- unreachable: Some(rgba(0x706c8cff).into()),
- unreachable_background: Some(rgba(0xdcd8d8ff).into()),
- unreachable_border: Some(rgba(0xdcd6d5ff).into()),
- warning: Some(rgba(0xe99d35ff).into()),
- warning_background: Some(rgba(0xffebd6ff).into()),
- warning_border: Some(rgba(0xffdab7ff).into()),
+ conflict: Some(rgba(0xf5c177ff).into()),
+ conflict_background: Some(rgba(0x50341aff).into()),
+ conflict_border: Some(rgba(0x6d4d2bff).into()),
+ created: Some(rgba(0x5dc2a3ff).into()),
+ created_background: Some(rgba(0x182e23ff).into()),
+ created_border: Some(rgba(0x254839ff).into()),
+ deleted: Some(rgba(0xea6f92ff).into()),
+ deleted_background: Some(rgba(0x431820ff).into()),
+ deleted_border: Some(rgba(0x612834ff).into()),
+ error: Some(rgba(0xea6f92ff).into()),
+ error_background: Some(rgba(0x431820ff).into()),
+ error_border: Some(rgba(0x612834ff).into()),
+ hidden: Some(rgba(0x2f2b43ff).into()),
+ hidden_background: Some(rgba(0x292739ff).into()),
+ hidden_border: Some(rgba(0x353347ff).into()),
+ hint: Some(rgba(0x5e768cff).into()),
+ hint_background: Some(rgba(0x2f3739ff).into()),
+ hint_border: Some(rgba(0x435255ff).into()),
+ ignored: Some(rgba(0x75718eff).into()),
+ ignored_background: Some(rgba(0x292739ff).into()),
+ ignored_border: Some(rgba(0x423f55ff).into()),
+ info: Some(rgba(0x9cced7ff).into()),
+ info_background: Some(rgba(0x2f3739ff).into()),
+ info_border: Some(rgba(0x435255ff).into()),
+ modified: Some(rgba(0xf5c177ff).into()),
+ modified_background: Some(rgba(0x50341aff).into()),
+ modified_border: Some(rgba(0x6d4d2bff).into()),
+ predictive: Some(rgba(0x556b81ff).into()),
+ predictive_background: Some(rgba(0x182e23ff).into()),
+ predictive_border: Some(rgba(0x254839ff).into()),
+ renamed: Some(rgba(0x9cced7ff).into()),
+ renamed_background: Some(rgba(0x2f3739ff).into()),
+ renamed_border: Some(rgba(0x435255ff).into()),
+ success: Some(rgba(0x5dc2a3ff).into()),
+ success_background: Some(rgba(0x182e23ff).into()),
+ success_border: Some(rgba(0x254839ff).into()),
+ unreachable: Some(rgba(0x75718eff).into()),
+ unreachable_background: Some(rgba(0x292739ff).into()),
+ unreachable_border: Some(rgba(0x423f55ff).into()),
+ warning: Some(rgba(0xf5c177ff).into()),
+ warning_background: Some(rgba(0x50341aff).into()),
+ warning_border: Some(rgba(0x6d4d2bff).into()),
..Default::default()
},
player: Some(PlayerColors(vec![
PlayerColor {
- cursor: rgba(0x57949fff).into(),
- background: rgba(0x57949fff).into(),
- selection: rgba(0x57949f3d).into(),
+ cursor: rgba(0x9cced7ff).into(),
+ background: rgba(0x9cced7ff).into(),
+ selection: rgba(0x9cced73d).into(),
},
PlayerColor {
- cursor: rgba(0x7c697fff).into(),
- background: rgba(0x7c697fff).into(),
- selection: rgba(0x7c697f3d).into(),
+ cursor: rgba(0x9d7691ff).into(),
+ background: rgba(0x9d7691ff).into(),
+ selection: rgba(0x9d76913d).into(),
},
PlayerColor {
- cursor: rgba(0x907aa9ff).into(),
- background: rgba(0x907aa9ff).into(),
- selection: rgba(0x907aa93d).into(),
+ cursor: rgba(0xc4a7e6ff).into(),
+ background: rgba(0xc4a7e6ff).into(),
+ selection: rgba(0xc4a7e63d).into(),
},
PlayerColor {
- cursor: rgba(0x907aa9ff).into(),
- background: rgba(0x907aa9ff).into(),
- selection: rgba(0x907aa93d).into(),
+ cursor: rgba(0xc4a7e6ff).into(),
+ background: rgba(0xc4a7e6ff).into(),
+ selection: rgba(0xc4a7e63d).into(),
},
PlayerColor {
- cursor: rgba(0x2a6983ff).into(),
- background: rgba(0x2a6983ff).into(),
- selection: rgba(0x2a69833d).into(),
+ cursor: rgba(0x32748fff).into(),
+ background: rgba(0x32748fff).into(),
+ selection: rgba(0x32748f3d).into(),
},
PlayerColor {
- cursor: rgba(0xb4647aff).into(),
- background: rgba(0xb4647aff).into(),
- selection: rgba(0xb4647a3d).into(),
+ cursor: rgba(0xea6f92ff).into(),
+ background: rgba(0xea6f92ff).into(),
+ selection: rgba(0xea6f923d).into(),
},
PlayerColor {
- cursor: rgba(0xe99d35ff).into(),
- background: rgba(0xe99d35ff).into(),
- selection: rgba(0xe99d353d).into(),
+ cursor: rgba(0xf5c177ff).into(),
+ background: rgba(0xf5c177ff).into(),
+ selection: rgba(0xf5c1773d).into(),
},
PlayerColor {
- cursor: rgba(0x3eaa8eff).into(),
- background: rgba(0x3eaa8eff).into(),
- selection: rgba(0x3eaa8e3d).into(),
+ cursor: rgba(0x5dc2a3ff).into(),
+ background: rgba(0x5dc2a3ff).into(),
+ selection: rgba(0x5dc2a33d).into(),
},
])),
syntax: Some(UserSyntaxTheme {
@@ -187,63 +187,63 @@ pub fn rose_pine() -> UserThemeFamily {
(
"attribute".into(),
UserHighlightStyle {
- color: Some(rgba(0x57949fff).into()),
+ color: Some(rgba(0x9cced7ff).into()),
..Default::default()
},
),
(
"boolean".into(),
UserHighlightStyle {
- color: Some(rgba(0xd7827eff).into()),
+ color: Some(rgba(0xebbcbaff).into()),
..Default::default()
},
),
(
"comment".into(),
UserHighlightStyle {
- color: Some(rgba(0x9893a5ff).into()),
+ color: Some(rgba(0x6e6a86ff).into()),
..Default::default()
},
),
(
"comment.doc".into(),
UserHighlightStyle {
- color: Some(rgba(0x6f6b8cff).into()),
+ color: Some(rgba(0x777390ff).into()),
..Default::default()
},
),
(
"constant".into(),
UserHighlightStyle {
- color: Some(rgba(0x3eaa8eff).into()),
+ color: Some(rgba(0x5dc2a3ff).into()),
..Default::default()
},
),
(
"constructor".into(),
UserHighlightStyle {
- color: Some(rgba(0x57949fff).into()),
+ color: Some(rgba(0x9cced7ff).into()),
..Default::default()
},
),
(
"embedded".into(),
UserHighlightStyle {
- color: Some(rgba(0x575279ff).into()),
+ color: Some(rgba(0xe0def4ff).into()),
..Default::default()
},
),
(
"emphasis".into(),
UserHighlightStyle {
- color: Some(rgba(0x57949fff).into()),
+ color: Some(rgba(0x9cced7ff).into()),
..Default::default()
},
),
(
"emphasis.strong".into(),
UserHighlightStyle {
- color: Some(rgba(0x57949fff).into()),
+ color: Some(rgba(0x9cced7ff).into()),
font_weight: Some(UserFontWeight(700.0)),
..Default::default()
},
@@ -251,28 +251,28 @@ pub fn rose_pine() -> UserThemeFamily {
(
"enum".into(),
UserHighlightStyle {
- color: Some(rgba(0x907aa9ff).into()),
+ color: Some(rgba(0xc4a7e6ff).into()),
..Default::default()
},
),
(
"function".into(),
UserHighlightStyle {
- color: Some(rgba(0xd7827eff).into()),
+ color: Some(rgba(0xebbcbaff).into()),
..Default::default()
},
),
(
"function.method".into(),
UserHighlightStyle {
- color: Some(rgba(0xd7827eff).into()),
+ color: Some(rgba(0xebbcbaff).into()),
..Default::default()
},
),
(
"hint".into(),
UserHighlightStyle {
- color: Some(rgba(0x7a92aaff).into()),
+ color: Some(rgba(0x5e768cff).into()),
font_weight: Some(UserFontWeight(700.0)),
..Default::default()
},
@@ -280,21 +280,21 @@ pub fn rose_pine() -> UserThemeFamily {
(
"keyword".into(),
UserHighlightStyle {
- color: Some(rgba(0x286983ff).into()),
+ color: Some(rgba(0x31748fff).into()),
..Default::default()
},
),
(
"label".into(),
UserHighlightStyle {
- color: Some(rgba(0x57949fff).into()),
+ color: Some(rgba(0x9cced7ff).into()),
..Default::default()
},
),
(
"link_text".into(),
UserHighlightStyle {
- color: Some(rgba(0x56949fff).into()),
+ color: Some(rgba(0x9ccfd8ff).into()),
font_style: Some(UserFontStyle::Normal),
..Default::default()
},
@@ -302,28 +302,28 @@ pub fn rose_pine() -> UserThemeFamily {
(
"link_uri".into(),
UserHighlightStyle {
- color: Some(rgba(0xd7827eff).into()),
+ color: Some(rgba(0xebbcbaff).into()),
..Default::default()
},
),
(
"number".into(),
UserHighlightStyle {
- color: Some(rgba(0x3eaa8eff).into()),
+ color: Some(rgba(0x5dc2a3ff).into()),
..Default::default()
},
),
(
"operator".into(),
UserHighlightStyle {
- color: Some(rgba(0x286983ff).into()),
+ color: Some(rgba(0x31748fff).into()),
..Default::default()
},
),
(
"predictive".into(),
UserHighlightStyle {
- color: Some(rgba(0xa2acbeff).into()),
+ color: Some(rgba(0x556b81ff).into()),
font_style: Some(UserFontStyle::Italic),
..Default::default()
},
@@ -331,112 +331,112 @@ pub fn rose_pine() -> UserThemeFamily {
(
"preproc".into(),
UserHighlightStyle {
- color: Some(rgba(0x575279ff).into()),
+ color: Some(rgba(0xe0def4ff).into()),
..Default::default()
},
),
(
"primary".into(),
UserHighlightStyle {
- color: Some(rgba(0x575279ff).into()),
+ color: Some(rgba(0xe0def4ff).into()),
..Default::default()
},
),
(
"property".into(),
UserHighlightStyle {
- color: Some(rgba(0x57949fff).into()),
+ color: Some(rgba(0x9cced7ff).into()),
..Default::default()
},
),
(
"punctuation".into(),
UserHighlightStyle {
- color: Some(rgba(0x797593ff).into()),
+ color: Some(rgba(0x908caaff).into()),
..Default::default()
},
),
(
"punctuation.bracket".into(),
UserHighlightStyle {
- color: Some(rgba(0x635e82ff).into()),
+ color: Some(rgba(0x9d99b6ff).into()),
..Default::default()
},
),
(
"punctuation.delimiter".into(),
UserHighlightStyle {
- color: Some(rgba(0x635e82ff).into()),
+ color: Some(rgba(0x9d99b6ff).into()),
..Default::default()
},
),
(
"punctuation.list_marker".into(),
UserHighlightStyle {
- color: Some(rgba(0x635e82ff).into()),
+ color: Some(rgba(0x9d99b6ff).into()),
..Default::default()
},
),
(
"punctuation.special".into(),
UserHighlightStyle {
- color: Some(rgba(0x635e82ff).into()),
+ color: Some(rgba(0x9d99b6ff).into()),
..Default::default()
},
),
(
"string".into(),
UserHighlightStyle {
- color: Some(rgba(0xea9d34ff).into()),
+ color: Some(rgba(0xf6c177ff).into()),
..Default::default()
},
),
(
"string.escape".into(),
UserHighlightStyle {
- color: Some(rgba(0x6f6b8cff).into()),
+ color: Some(rgba(0x777390ff).into()),
..Default::default()
},
),
(
"string.regex".into(),
UserHighlightStyle {
- color: Some(rgba(0x907aa9ff).into()),
+ color: Some(rgba(0xc4a7e6ff).into()),
..Default::default()
},
),
(
"string.special".into(),
UserHighlightStyle {
- color: Some(rgba(0x907aa9ff).into()),
+ color: Some(rgba(0xc4a7e6ff).into()),
..Default::default()
},
),
(
"string.special.symbol".into(),
UserHighlightStyle {
- color: Some(rgba(0x907aa9ff).into()),
+ color: Some(rgba(0xc4a7e6ff).into()),
..Default::default()
},
),
(
"tag".into(),
UserHighlightStyle {
- color: Some(rgba(0x56949fff).into()),
+ color: Some(rgba(0x9ccfd8ff).into()),
..Default::default()
},
),
(
"text.literal".into(),
UserHighlightStyle {
- color: Some(rgba(0x907aa9ff).into()),
+ color: Some(rgba(0xc4a7e6ff).into()),
..Default::default()
},
),
(
"title".into(),
UserHighlightStyle {
- color: Some(rgba(0xea9d34ff).into()),
+ color: Some(rgba(0xf6c177ff).into()),
font_weight: Some(UserFontWeight(700.0)),
..Default::default()
},
@@ -444,28 +444,28 @@ pub fn rose_pine() -> UserThemeFamily {
(
"type".into(),
UserHighlightStyle {
- color: Some(rgba(0x56949fff).into()),
+ color: Some(rgba(0x9ccfd8ff).into()),
..Default::default()
},
),
(
"type.builtin".into(),
UserHighlightStyle {
- color: Some(rgba(0x56949fff).into()),
+ color: Some(rgba(0x9ccfd8ff).into()),
..Default::default()
},
),
(
"variable".into(),
UserHighlightStyle {
- color: Some(rgba(0x575279ff).into()),
+ color: Some(rgba(0xe0def4ff).into()),
..Default::default()
},
),
(
"variant".into(),
UserHighlightStyle {
- color: Some(rgba(0x57949fff).into()),
+ color: Some(rgba(0x9cced7ff).into()),
..Default::default()
},
),
@@ -474,170 +474,170 @@ pub fn rose_pine() -> UserThemeFamily {
},
},
UserTheme {
- name: "Rosé Pine Moon".into(),
- appearance: Appearance::Dark,
+ name: "Rosé Pine Dawn".into(),
+ appearance: Appearance::Light,
styles: UserThemeStylesRefinement {
colors: ThemeColorsRefinement {
- border: Some(rgba(0x504c68ff).into()),
- border_variant: Some(rgba(0x322f48ff).into()),
- border_focused: Some(rgba(0x435255ff).into()),
- border_selected: Some(rgba(0x435255ff).into()),
+ border: Some(rgba(0xdcd6d5ff).into()),
+ border_variant: Some(rgba(0xe5e0dfff).into()),
+ border_focused: Some(rgba(0xc3d7dbff).into()),
+ border_selected: Some(rgba(0xc3d7dbff).into()),
border_transparent: Some(rgba(0x00000000).into()),
- border_disabled: Some(rgba(0x44415bff).into()),
- elevated_surface_background: Some(rgba(0x28253cff).into()),
- surface_background: Some(rgba(0x28253cff).into()),
- background: Some(rgba(0x38354eff).into()),
- panel_background: Some(rgba(0x28253cff).into()),
- element_background: Some(rgba(0x28253cff).into()),
- element_hover: Some(rgba(0x322f48ff).into()),
- element_active: Some(rgba(0x4f4b66ff).into()),
- element_selected: Some(rgba(0x4f4b66ff).into()),
- element_disabled: Some(rgba(0x28253cff).into()),
- drop_target_background: Some(rgba(0x85819e80).into()),
+ border_disabled: Some(rgba(0xd0cccfff).into()),
+ elevated_surface_background: Some(rgba(0xfef9f2ff).into()),
+ surface_background: Some(rgba(0xfef9f2ff).into()),
+ background: Some(rgba(0xdcd8d8ff).into()),
+ panel_background: Some(rgba(0xfef9f2ff).into()),
+ element_background: Some(rgba(0xfef9f2ff).into()),
+ element_hover: Some(rgba(0xe5e0dfff).into()),
+ element_active: Some(rgba(0xdbd5d4ff).into()),
+ element_selected: Some(rgba(0xdbd5d4ff).into()),
+ element_disabled: Some(rgba(0xfef9f2ff).into()),
+ drop_target_background: Some(rgba(0x706c8c80).into()),
ghost_element_background: Some(rgba(0x00000000).into()),
- ghost_element_hover: Some(rgba(0x322f48ff).into()),
- ghost_element_active: Some(rgba(0x4f4b66ff).into()),
- ghost_element_selected: Some(rgba(0x4f4b66ff).into()),
- ghost_element_disabled: Some(rgba(0x28253cff).into()),
- text: Some(rgba(0xe0def4ff).into()),
- text_muted: Some(rgba(0x85819eff).into()),
- text_placeholder: Some(rgba(0x615d7aff).into()),
- text_disabled: Some(rgba(0x615d7aff).into()),
- text_accent: Some(rgba(0x9cced7ff).into()),
- icon: Some(rgba(0xe0def4ff).into()),
- icon_muted: Some(rgba(0x85819eff).into()),
- icon_disabled: Some(rgba(0x615d7aff).into()),
- icon_placeholder: Some(rgba(0x85819eff).into()),
- icon_accent: Some(rgba(0x9cced7ff).into()),
- status_bar_background: Some(rgba(0x38354eff).into()),
- title_bar_background: Some(rgba(0x38354eff).into()),
- toolbar_background: Some(rgba(0x232136ff).into()),
- tab_bar_background: Some(rgba(0x28253cff).into()),
- tab_inactive_background: Some(rgba(0x28253cff).into()),
- tab_active_background: Some(rgba(0x232136ff).into()),
- scrollbar_thumb_background: Some(rgba(0xe0def44c).into()),
- scrollbar_thumb_hover_background: Some(rgba(0x322f48ff).into()),
- scrollbar_thumb_border: Some(rgba(0x322f48ff).into()),
+ ghost_element_hover: Some(rgba(0xe5e0dfff).into()),
+ ghost_element_active: Some(rgba(0xdbd5d4ff).into()),
+ ghost_element_selected: Some(rgba(0xdbd5d4ff).into()),
+ ghost_element_disabled: Some(rgba(0xfef9f2ff).into()),
+ text: Some(rgba(0x575279ff).into()),
+ text_muted: Some(rgba(0x706c8cff).into()),
+ text_placeholder: Some(rgba(0x938fa3ff).into()),
+ text_disabled: Some(rgba(0x938fa3ff).into()),
+ text_accent: Some(rgba(0x57949fff).into()),
+ icon: Some(rgba(0x575279ff).into()),
+ icon_muted: Some(rgba(0x706c8cff).into()),
+ icon_disabled: Some(rgba(0x938fa3ff).into()),
+ icon_placeholder: Some(rgba(0x706c8cff).into()),
+ icon_accent: Some(rgba(0x57949fff).into()),
+ status_bar_background: Some(rgba(0xdcd8d8ff).into()),
+ title_bar_background: Some(rgba(0xdcd8d8ff).into()),
+ toolbar_background: Some(rgba(0xfaf4edff).into()),
+ tab_bar_background: Some(rgba(0xfef9f2ff).into()),
+ tab_inactive_background: Some(rgba(0xfef9f2ff).into()),
+ tab_active_background: Some(rgba(0xfaf4edff).into()),
+ scrollbar_thumb_background: Some(rgba(0x5752794c).into()),
+ scrollbar_thumb_hover_background: Some(rgba(0xe5e0dfff).into()),
+ scrollbar_thumb_border: Some(rgba(0xe5e0dfff).into()),
scrollbar_track_background: Some(rgba(0x00000000).into()),
- scrollbar_track_border: Some(rgba(0x27243bff).into()),
- editor_foreground: Some(rgba(0xe0def4ff).into()),
- editor_background: Some(rgba(0x232136ff).into()),
- editor_gutter_background: Some(rgba(0x232136ff).into()),
- editor_subheader_background: Some(rgba(0x28253cff).into()),
- editor_active_line_background: Some(rgba(0x28253cbf).into()),
- editor_highlighted_line_background: Some(rgba(0x28253cff).into()),
- editor_line_number: Some(rgba(0xe0def459).into()),
- editor_active_line_number: Some(rgba(0xe0def4ff).into()),
- editor_invisible: Some(rgba(0x85819eff).into()),
- editor_wrap_guide: Some(rgba(0xe0def40d).into()),
- editor_active_wrap_guide: Some(rgba(0xe0def41a).into()),
- editor_document_highlight_read_background: Some(rgba(0x9cced71a).into()),
- editor_document_highlight_write_background: Some(rgba(0x59557166).into()),
- terminal_background: Some(rgba(0x232136ff).into()),
- terminal_ansi_bright_black: Some(rgba(0x3f3b58ff).into()),
- terminal_ansi_bright_red: Some(rgba(0x7e3647ff).into()),
- terminal_ansi_bright_green: Some(rgba(0x31614fff).into()),
- terminal_ansi_bright_yellow: Some(rgba(0x8a653bff).into()),
- terminal_ansi_bright_blue: Some(rgba(0x566c70ff).into()),
- terminal_ansi_bright_magenta: Some(rgba(0x51414eff).into()),
- terminal_ansi_bright_cyan: Some(rgba(0x264654ff).into()),
- terminal_ansi_bright_white: Some(rgba(0xe0def4ff).into()),
- terminal_ansi_black: Some(rgba(0x232136ff).into()),
- terminal_ansi_red: Some(rgba(0xea6f92ff).into()),
- terminal_ansi_green: Some(rgba(0x5dc2a3ff).into()),
- terminal_ansi_yellow: Some(rgba(0xf5c177ff).into()),
- terminal_ansi_blue: Some(rgba(0x9cced7ff).into()),
- terminal_ansi_magenta: Some(rgba(0xa784a1ff).into()),
- terminal_ansi_cyan: Some(rgba(0x3f8fb0ff).into()),
- terminal_ansi_white: Some(rgba(0xe0def4ff).into()),
- link_text_hover: Some(rgba(0x9cced7ff).into()),
+ scrollbar_track_border: Some(rgba(0xfdf8f1ff).into()),
+ editor_foreground: Some(rgba(0x575279ff).into()),
+ editor_background: Some(rgba(0xfaf4edff).into()),
+ editor_gutter_background: Some(rgba(0xfaf4edff).into()),
+ editor_subheader_background: Some(rgba(0xfef9f2ff).into()),
+ editor_active_line_background: Some(rgba(0xfef9f2bf).into()),
+ editor_highlighted_line_background: Some(rgba(0xfef9f2ff).into()),
+ editor_line_number: Some(rgba(0x57527959).into()),
+ editor_active_line_number: Some(rgba(0x575279ff).into()),
+ editor_invisible: Some(rgba(0x706c8cff).into()),
+ editor_wrap_guide: Some(rgba(0x5752790d).into()),
+ editor_active_wrap_guide: Some(rgba(0x5752791a).into()),
+ editor_document_highlight_read_background: Some(rgba(0x57949f1a).into()),
+ editor_document_highlight_write_background: Some(rgba(0x9691a466).into()),
+ terminal_background: Some(rgba(0xfaf4edff).into()),
+ terminal_ansi_bright_black: Some(rgba(0xb8b2baff).into()),
+ terminal_ansi_bright_red: Some(rgba(0xdcb0bbff).into()),
+ terminal_ansi_bright_green: Some(rgba(0xa5d5c5ff).into()),
+ terminal_ansi_bright_yellow: Some(rgba(0xfccd9bff).into()),
+ terminal_ansi_bright_blue: Some(rgba(0xacc9ceff).into()),
+ terminal_ansi_bright_magenta: Some(rgba(0xbcb1bdff).into()),
+ terminal_ansi_bright_cyan: Some(rgba(0x97b1c0ff).into()),
+ terminal_ansi_bright_white: Some(rgba(0x575279ff).into()),
+ terminal_ansi_black: Some(rgba(0xfaf4edff).into()),
+ terminal_ansi_red: Some(rgba(0xb4647aff).into()),
+ terminal_ansi_green: Some(rgba(0x3eaa8eff).into()),
+ terminal_ansi_yellow: Some(rgba(0xe99d35ff).into()),
+ terminal_ansi_blue: Some(rgba(0x57949fff).into()),
+ terminal_ansi_magenta: Some(rgba(0x7c697fff).into()),
+ terminal_ansi_cyan: Some(rgba(0x2a6983ff).into()),
+ terminal_ansi_white: Some(rgba(0x575279ff).into()),
+ link_text_hover: Some(rgba(0x57949fff).into()),
..Default::default()
},
status: StatusColorsRefinement {
- conflict: Some(rgba(0xf5c177ff).into()),
- conflict_background: Some(rgba(0x50341aff).into()),
- conflict_border: Some(rgba(0x6d4d2bff).into()),
- created: Some(rgba(0x5dc2a3ff).into()),
- created_background: Some(rgba(0x182e23ff).into()),
- created_border: Some(rgba(0x254839ff).into()),
- deleted: Some(rgba(0xea6f92ff).into()),
- deleted_background: Some(rgba(0x431820ff).into()),
- deleted_border: Some(rgba(0x612834ff).into()),
- error: Some(rgba(0xea6f92ff).into()),
- error_background: Some(rgba(0x431820ff).into()),
- error_border: Some(rgba(0x612834ff).into()),
- hidden: Some(rgba(0x615d7aff).into()),
- hidden_background: Some(rgba(0x38354eff).into()),
- hidden_border: Some(rgba(0x44415bff).into()),
- hint: Some(rgba(0x728aa2ff).into()),
- hint_background: Some(rgba(0x2f3739ff).into()),
- hint_border: Some(rgba(0x435255ff).into()),
- ignored: Some(rgba(0x85819eff).into()),
- ignored_background: Some(rgba(0x38354eff).into()),
- ignored_border: Some(rgba(0x504c68ff).into()),
- info: Some(rgba(0x9cced7ff).into()),
- info_background: Some(rgba(0x2f3739ff).into()),
- info_border: Some(rgba(0x435255ff).into()),
- modified: Some(rgba(0xf5c177ff).into()),
- modified_background: Some(rgba(0x50341aff).into()),
- modified_border: Some(rgba(0x6d4d2bff).into()),
- predictive: Some(rgba(0x516b83ff).into()),
- predictive_background: Some(rgba(0x182e23ff).into()),
- predictive_border: Some(rgba(0x254839ff).into()),
- renamed: Some(rgba(0x9cced7ff).into()),
- renamed_background: Some(rgba(0x2f3739ff).into()),
- renamed_border: Some(rgba(0x435255ff).into()),
- success: Some(rgba(0x5dc2a3ff).into()),
- success_background: Some(rgba(0x182e23ff).into()),
- success_border: Some(rgba(0x254839ff).into()),
- unreachable: Some(rgba(0x85819eff).into()),
- unreachable_background: Some(rgba(0x38354eff).into()),
- unreachable_border: Some(rgba(0x504c68ff).into()),
- warning: Some(rgba(0xf5c177ff).into()),
- warning_background: Some(rgba(0x50341aff).into()),
- warning_border: Some(rgba(0x6d4d2bff).into()),
+ conflict: Some(rgba(0xe99d35ff).into()),
+ conflict_background: Some(rgba(0xffebd6ff).into()),
+ conflict_border: Some(rgba(0xffdab7ff).into()),
+ created: Some(rgba(0x3eaa8eff).into()),
+ created_background: Some(rgba(0xdbeee7ff).into()),
+ created_border: Some(rgba(0xbee0d5ff).into()),
+ deleted: Some(rgba(0xb4647aff).into()),
+ deleted_background: Some(rgba(0xf1dfe3ff).into()),
+ deleted_border: Some(rgba(0xe6c6cdff).into()),
+ error: Some(rgba(0xb4647aff).into()),
+ error_background: Some(rgba(0xf1dfe3ff).into()),
+ error_border: Some(rgba(0xe6c6cdff).into()),
+ hidden: Some(rgba(0x938fa3ff).into()),
+ hidden_background: Some(rgba(0xdcd8d8ff).into()),
+ hidden_border: Some(rgba(0xd0cccfff).into()),
+ hint: Some(rgba(0x7a92aaff).into()),
+ hint_background: Some(rgba(0xdde9ebff).into()),
+ hint_border: Some(rgba(0xc3d7dbff).into()),
+ ignored: Some(rgba(0x706c8cff).into()),
+ ignored_background: Some(rgba(0xdcd8d8ff).into()),
+ ignored_border: Some(rgba(0xdcd6d5ff).into()),
+ info: Some(rgba(0x57949fff).into()),
+ info_background: Some(rgba(0xdde9ebff).into()),
+ info_border: Some(rgba(0xc3d7dbff).into()),
+ modified: Some(rgba(0xe99d35ff).into()),
+ modified_background: Some(rgba(0xffebd6ff).into()),
+ modified_border: Some(rgba(0xffdab7ff).into()),
+ predictive: Some(rgba(0xa2acbeff).into()),
+ predictive_background: Some(rgba(0xdbeee7ff).into()),
+ predictive_border: Some(rgba(0xbee0d5ff).into()),
+ renamed: Some(rgba(0x57949fff).into()),
+ renamed_background: Some(rgba(0xdde9ebff).into()),
+ renamed_border: Some(rgba(0xc3d7dbff).into()),
+ success: Some(rgba(0x3eaa8eff).into()),
+ success_background: Some(rgba(0xdbeee7ff).into()),
+ success_border: Some(rgba(0xbee0d5ff).into()),
+ unreachable: Some(rgba(0x706c8cff).into()),
+ unreachable_background: Some(rgba(0xdcd8d8ff).into()),
+ unreachable_border: Some(rgba(0xdcd6d5ff).into()),
+ warning: Some(rgba(0xe99d35ff).into()),
+ warning_background: Some(rgba(0xffebd6ff).into()),
+ warning_border: Some(rgba(0xffdab7ff).into()),
..Default::default()
},
player: Some(PlayerColors(vec![
PlayerColor {
- cursor: rgba(0x9cced7ff).into(),
- background: rgba(0x9cced7ff).into(),
- selection: rgba(0x9cced73d).into(),
+ cursor: rgba(0x57949fff).into(),
+ background: rgba(0x57949fff).into(),
+ selection: rgba(0x57949f3d).into(),
},
PlayerColor {
- cursor: rgba(0xa784a1ff).into(),
- background: rgba(0xa784a1ff).into(),
- selection: rgba(0xa784a13d).into(),
+ cursor: rgba(0x7c697fff).into(),
+ background: rgba(0x7c697fff).into(),
+ selection: rgba(0x7c697f3d).into(),
},
PlayerColor {
- cursor: rgba(0xc4a7e6ff).into(),
- background: rgba(0xc4a7e6ff).into(),
- selection: rgba(0xc4a7e63d).into(),
+ cursor: rgba(0x907aa9ff).into(),
+ background: rgba(0x907aa9ff).into(),
+ selection: rgba(0x907aa93d).into(),
},
PlayerColor {
- cursor: rgba(0xc4a7e6ff).into(),
- background: rgba(0xc4a7e6ff).into(),
- selection: rgba(0xc4a7e63d).into(),
+ cursor: rgba(0x907aa9ff).into(),
+ background: rgba(0x907aa9ff).into(),
+ selection: rgba(0x907aa93d).into(),
},
PlayerColor {
- cursor: rgba(0x3f8fb0ff).into(),
- background: rgba(0x3f8fb0ff).into(),
- selection: rgba(0x3f8fb03d).into(),
+ cursor: rgba(0x2a6983ff).into(),
+ background: rgba(0x2a6983ff).into(),
+ selection: rgba(0x2a69833d).into(),
},
PlayerColor {
- cursor: rgba(0xea6f92ff).into(),
- background: rgba(0xea6f92ff).into(),
- selection: rgba(0xea6f923d).into(),
+ cursor: rgba(0xb4647aff).into(),
+ background: rgba(0xb4647aff).into(),
+ selection: rgba(0xb4647a3d).into(),
},
PlayerColor {
- cursor: rgba(0xf5c177ff).into(),
- background: rgba(0xf5c177ff).into(),
- selection: rgba(0xf5c1773d).into(),
+ cursor: rgba(0xe99d35ff).into(),
+ background: rgba(0xe99d35ff).into(),
+ selection: rgba(0xe99d353d).into(),
},
PlayerColor {
- cursor: rgba(0x5dc2a3ff).into(),
- background: rgba(0x5dc2a3ff).into(),
- selection: rgba(0x5dc2a33d).into(),
+ cursor: rgba(0x3eaa8eff).into(),
+ background: rgba(0x3eaa8eff).into(),
+ selection: rgba(0x3eaa8e3d).into(),
},
])),
syntax: Some(UserSyntaxTheme {
@@ -645,63 +645,63 @@ pub fn rose_pine() -> UserThemeFamily {
(
"attribute".into(),
UserHighlightStyle {
- color: Some(rgba(0x9cced7ff).into()),
+ color: Some(rgba(0x57949fff).into()),
..Default::default()
},
),
(
"boolean".into(),
UserHighlightStyle {
- color: Some(rgba(0xea9a97ff).into()),
+ color: Some(rgba(0xd7827eff).into()),
..Default::default()
},
),
(
"comment".into(),
UserHighlightStyle {
- color: Some(rgba(0x6e6a86ff).into()),
+ color: Some(rgba(0x9893a5ff).into()),
..Default::default()
},
),
(
"comment.doc".into(),
UserHighlightStyle {
- color: Some(rgba(0x8682a0ff).into()),
+ color: Some(rgba(0x6f6b8cff).into()),
..Default::default()
},
),
(
"constant".into(),
UserHighlightStyle {
- color: Some(rgba(0x5dc2a3ff).into()),
+ color: Some(rgba(0x3eaa8eff).into()),
..Default::default()
},
),
(
"constructor".into(),
UserHighlightStyle {
- color: Some(rgba(0x9cced7ff).into()),
+ color: Some(rgba(0x57949fff).into()),
..Default::default()
},
),
(
"embedded".into(),
UserHighlightStyle {
- color: Some(rgba(0xe0def4ff).into()),
+ color: Some(rgba(0x575279ff).into()),
..Default::default()
},
),
(
"emphasis".into(),
UserHighlightStyle {
- color: Some(rgba(0x9cced7ff).into()),
+ color: Some(rgba(0x57949fff).into()),
..Default::default()
},
),
(
"emphasis.strong".into(),
UserHighlightStyle {
- color: Some(rgba(0x9cced7ff).into()),
+ color: Some(rgba(0x57949fff).into()),
font_weight: Some(UserFontWeight(700.0)),
..Default::default()
},
@@ -16,150 +16,150 @@ pub fn solarized() -> UserThemeFamily {
author: "Zed Industries".into(),
themes: vec![
UserTheme {
- name: "Solarized Light".into(),
- appearance: Appearance::Light,
+ name: "Solarized Dark".into(),
+ appearance: Appearance::Dark,
styles: UserThemeStylesRefinement {
colors: ThemeColorsRefinement {
- border: Some(rgba(0x9faaa8ff).into()),
- border_variant: Some(rgba(0xdcdacbff).into()),
- border_focused: Some(rgba(0xbfd3efff).into()),
- border_selected: Some(rgba(0xbfd3efff).into()),
+ border: Some(rgba(0x2b4f58ff).into()),
+ border_variant: Some(rgba(0x063541ff).into()),
+ border_focused: Some(rgba(0x1c3249ff).into()),
+ border_selected: Some(rgba(0x1c3249ff).into()),
border_transparent: Some(rgba(0x00000000).into()),
- border_disabled: Some(rgba(0xb7bdb6ff).into()),
- elevated_surface_background: Some(rgba(0xf3eddaff).into()),
- surface_background: Some(rgba(0xf3eddaff).into()),
- background: Some(rgba(0xcfd0c4ff).into()),
- panel_background: Some(rgba(0xf3eddaff).into()),
- element_background: Some(rgba(0xf3eddaff).into()),
- element_hover: Some(rgba(0xdcdacbff).into()),
- element_active: Some(rgba(0xa2aca9ff).into()),
- element_selected: Some(rgba(0xa2aca9ff).into()),
- element_disabled: Some(rgba(0xf3eddaff).into()),
- drop_target_background: Some(rgba(0x34555e80).into()),
+ border_disabled: Some(rgba(0x19424dff).into()),
+ elevated_surface_background: Some(rgba(0x04313cff).into()),
+ surface_background: Some(rgba(0x04313cff).into()),
+ background: Some(rgba(0x083743ff).into()),
+ panel_background: Some(rgba(0x04313cff).into()),
+ element_background: Some(rgba(0x04313cff).into()),
+ element_hover: Some(rgba(0x063541ff).into()),
+ element_active: Some(rgba(0x294e58ff).into()),
+ element_selected: Some(rgba(0x294e58ff).into()),
+ element_disabled: Some(rgba(0x04313cff).into()),
+ drop_target_background: Some(rgba(0x93a1a180).into()),
ghost_element_background: Some(rgba(0x00000000).into()),
- ghost_element_hover: Some(rgba(0xdcdacbff).into()),
- ghost_element_active: Some(rgba(0xa2aca9ff).into()),
- ghost_element_selected: Some(rgba(0xa2aca9ff).into()),
- ghost_element_disabled: Some(rgba(0xf3eddaff).into()),
- text: Some(rgba(0x002b36ff).into()),
- text_muted: Some(rgba(0x34555eff).into()),
- text_placeholder: Some(rgba(0x6a7f86ff).into()),
- text_disabled: Some(rgba(0x6a7f86ff).into()),
- text_accent: Some(rgba(0x298bd1ff).into()),
- icon: Some(rgba(0x002b36ff).into()),
- icon_muted: Some(rgba(0x34555eff).into()),
- icon_disabled: Some(rgba(0x6a7f86ff).into()),
- icon_placeholder: Some(rgba(0x34555eff).into()),
- icon_accent: Some(rgba(0x298bd1ff).into()),
- status_bar_background: Some(rgba(0xcfd0c4ff).into()),
- title_bar_background: Some(rgba(0xcfd0c4ff).into()),
- toolbar_background: Some(rgba(0xfdf6e3ff).into()),
- tab_bar_background: Some(rgba(0xf3eddaff).into()),
- tab_inactive_background: Some(rgba(0xf3eddaff).into()),
- tab_active_background: Some(rgba(0xfdf6e3ff).into()),
- scrollbar_thumb_background: Some(rgba(0x002b364c).into()),
- scrollbar_thumb_hover_background: Some(rgba(0xdcdacbff).into()),
- scrollbar_thumb_border: Some(rgba(0xdcdacbff).into()),
+ ghost_element_hover: Some(rgba(0x063541ff).into()),
+ ghost_element_active: Some(rgba(0x294e58ff).into()),
+ ghost_element_selected: Some(rgba(0x294e58ff).into()),
+ ghost_element_disabled: Some(rgba(0x04313cff).into()),
+ text: Some(rgba(0xfdf6e3ff).into()),
+ text_muted: Some(rgba(0x93a1a1ff).into()),
+ text_placeholder: Some(rgba(0x6f8389ff).into()),
+ text_disabled: Some(rgba(0x6f8389ff).into()),
+ text_accent: Some(rgba(0x288bd1ff).into()),
+ icon: Some(rgba(0xfdf6e3ff).into()),
+ icon_muted: Some(rgba(0x93a1a1ff).into()),
+ icon_disabled: Some(rgba(0x6f8389ff).into()),
+ icon_placeholder: Some(rgba(0x93a1a1ff).into()),
+ icon_accent: Some(rgba(0x288bd1ff).into()),
+ status_bar_background: Some(rgba(0x083743ff).into()),
+ title_bar_background: Some(rgba(0x083743ff).into()),
+ toolbar_background: Some(rgba(0x002b36ff).into()),
+ tab_bar_background: Some(rgba(0x04313cff).into()),
+ tab_inactive_background: Some(rgba(0x04313cff).into()),
+ tab_active_background: Some(rgba(0x002b36ff).into()),
+ scrollbar_thumb_background: Some(rgba(0xfdf6e34c).into()),
+ scrollbar_thumb_hover_background: Some(rgba(0x063541ff).into()),
+ scrollbar_thumb_border: Some(rgba(0x063541ff).into()),
scrollbar_track_background: Some(rgba(0x00000000).into()),
- scrollbar_track_border: Some(rgba(0xf5eedbff).into()),
- editor_foreground: Some(rgba(0x002b36ff).into()),
- editor_background: Some(rgba(0xfdf6e3ff).into()),
- editor_gutter_background: Some(rgba(0xfdf6e3ff).into()),
- editor_subheader_background: Some(rgba(0xf3eddaff).into()),
- editor_active_line_background: Some(rgba(0xf3eddabf).into()),
- editor_highlighted_line_background: Some(rgba(0xf3eddaff).into()),
- editor_line_number: Some(rgba(0x002b3659).into()),
- editor_active_line_number: Some(rgba(0x002b36ff).into()),
- editor_invisible: Some(rgba(0x34555eff).into()),
- editor_wrap_guide: Some(rgba(0x002b360d).into()),
- editor_active_wrap_guide: Some(rgba(0x002b361a).into()),
- editor_document_highlight_read_background: Some(rgba(0x298bd11a).into()),
+ scrollbar_track_border: Some(rgba(0x032f3bff).into()),
+ editor_foreground: Some(rgba(0xfdf6e3ff).into()),
+ editor_background: Some(rgba(0x002b36ff).into()),
+ editor_gutter_background: Some(rgba(0x002b36ff).into()),
+ editor_subheader_background: Some(rgba(0x04313cff).into()),
+ editor_active_line_background: Some(rgba(0x04313cbf).into()),
+ editor_highlighted_line_background: Some(rgba(0x04313cff).into()),
+ editor_line_number: Some(rgba(0xfdf6e359).into()),
+ editor_active_line_number: Some(rgba(0xfdf6e3ff).into()),
+ editor_invisible: Some(rgba(0x93a1a1ff).into()),
+ editor_wrap_guide: Some(rgba(0xfdf6e30d).into()),
+ editor_active_wrap_guide: Some(rgba(0xfdf6e31a).into()),
+ editor_document_highlight_read_background: Some(rgba(0x288bd11a).into()),
editor_document_highlight_write_background: Some(rgba(0x6d828866).into()),
- terminal_background: Some(rgba(0xfdf6e3ff).into()),
- terminal_ansi_bright_black: Some(rgba(0x7b8e91ff).into()),
- terminal_ansi_bright_red: Some(rgba(0xfaa091ff).into()),
- terminal_ansi_bright_green: Some(rgba(0xc6cb8bff).into()),
- terminal_ansi_bright_yellow: Some(rgba(0xe1c28aff).into()),
- terminal_ansi_bright_blue: Some(rgba(0xa5c3e9ff).into()),
- terminal_ansi_bright_magenta: Some(rgba(0xf0a2bfff).into()),
- terminal_ansi_bright_cyan: Some(rgba(0x9fd0cbff).into()),
- terminal_ansi_bright_white: Some(rgba(0x002b36ff).into()),
- terminal_ansi_black: Some(rgba(0xfdf6e3ff).into()),
+ terminal_background: Some(rgba(0x002b36ff).into()),
+ terminal_ansi_bright_black: Some(rgba(0x5c7279ff).into()),
+ terminal_ansi_bright_red: Some(rgba(0x7d181cff).into()),
+ terminal_ansi_bright_green: Some(rgba(0x434a11ff).into()),
+ terminal_ansi_bright_yellow: Some(rgba(0x5d4310ff).into()),
+ terminal_ansi_bright_blue: Some(rgba(0x214465ff).into()),
+ terminal_ansi_bright_magenta: Some(rgba(0x6f1f40ff).into()),
+ terminal_ansi_bright_cyan: Some(rgba(0x204e4aff).into()),
+ terminal_ansi_bright_white: Some(rgba(0xfdf6e3ff).into()),
+ terminal_ansi_black: Some(rgba(0x002b36ff).into()),
terminal_ansi_red: Some(rgba(0xdc3330ff).into()),
terminal_ansi_green: Some(rgba(0x859904ff).into()),
- terminal_ansi_yellow: Some(rgba(0xb58904ff).into()),
- terminal_ansi_blue: Some(rgba(0x298bd1ff).into()),
- terminal_ansi_magenta: Some(rgba(0xd33882ff).into()),
+ terminal_ansi_yellow: Some(rgba(0xb58903ff).into()),
+ terminal_ansi_blue: Some(rgba(0x288bd1ff).into()),
+ terminal_ansi_magenta: Some(rgba(0xd33782ff).into()),
terminal_ansi_cyan: Some(rgba(0x2ca198ff).into()),
- terminal_ansi_white: Some(rgba(0x002b36ff).into()),
- link_text_hover: Some(rgba(0x298bd1ff).into()),
+ terminal_ansi_white: Some(rgba(0xfdf6e3ff).into()),
+ link_text_hover: Some(rgba(0x288bd1ff).into()),
..Default::default()
},
status: StatusColorsRefinement {
- conflict: Some(rgba(0xb58904ff).into()),
- conflict_background: Some(rgba(0xf5e6d0ff).into()),
- conflict_border: Some(rgba(0xebd3aaff).into()),
+ conflict: Some(rgba(0xb58903ff).into()),
+ conflict_background: Some(rgba(0x2f1e0cff).into()),
+ conflict_border: Some(rgba(0x473110ff).into()),
created: Some(rgba(0x859904ff).into()),
- created_background: Some(rgba(0xe9ead0ff).into()),
- created_border: Some(rgba(0xd6d9abff).into()),
+ created_background: Some(rgba(0x1f210cff).into()),
+ created_border: Some(rgba(0x323610ff).into()),
deleted: Some(rgba(0xdc3330ff).into()),
- deleted_background: Some(rgba(0xffd9d2ff).into()),
- deleted_border: Some(rgba(0xffbbafff).into()),
+ deleted_background: Some(rgba(0x4a090fff).into()),
+ deleted_border: Some(rgba(0x641116ff).into()),
error: Some(rgba(0xdc3330ff).into()),
- error_background: Some(rgba(0xffd9d2ff).into()),
- error_border: Some(rgba(0xffbbafff).into()),
- hidden: Some(rgba(0x6a7f86ff).into()),
- hidden_background: Some(rgba(0xcfd0c4ff).into()),
- hidden_border: Some(rgba(0xb7bdb6ff).into()),
- hint: Some(rgba(0x5889a3ff).into()),
- hint_background: Some(rgba(0xdbe6f6ff).into()),
- hint_border: Some(rgba(0xbfd3efff).into()),
- ignored: Some(rgba(0x34555eff).into()),
- ignored_background: Some(rgba(0xcfd0c4ff).into()),
- ignored_border: Some(rgba(0x9faaa8ff).into()),
- info: Some(rgba(0x298bd1ff).into()),
- info_background: Some(rgba(0xdbe6f6ff).into()),
- info_border: Some(rgba(0xbfd3efff).into()),
- modified: Some(rgba(0xb58904ff).into()),
- modified_background: Some(rgba(0xf5e6d0ff).into()),
- modified_border: Some(rgba(0xebd3aaff).into()),
- predictive: Some(rgba(0x679aafff).into()),
- predictive_background: Some(rgba(0xe9ead0ff).into()),
- predictive_border: Some(rgba(0xd6d9abff).into()),
- renamed: Some(rgba(0x298bd1ff).into()),
- renamed_background: Some(rgba(0xdbe6f6ff).into()),
- renamed_border: Some(rgba(0xbfd3efff).into()),
+ error_background: Some(rgba(0x4a090fff).into()),
+ error_border: Some(rgba(0x641116ff).into()),
+ hidden: Some(rgba(0x6f8389ff).into()),
+ hidden_background: Some(rgba(0x083743ff).into()),
+ hidden_border: Some(rgba(0x19424dff).into()),
+ hint: Some(rgba(0x4f8297ff).into()),
+ hint_background: Some(rgba(0x141f2cff).into()),
+ hint_border: Some(rgba(0x1c3249ff).into()),
+ ignored: Some(rgba(0x93a1a1ff).into()),
+ ignored_background: Some(rgba(0x083743ff).into()),
+ ignored_border: Some(rgba(0x2b4f58ff).into()),
+ info: Some(rgba(0x288bd1ff).into()),
+ info_background: Some(rgba(0x141f2cff).into()),
+ info_border: Some(rgba(0x1c3249ff).into()),
+ modified: Some(rgba(0xb58903ff).into()),
+ modified_background: Some(rgba(0x2f1e0cff).into()),
+ modified_border: Some(rgba(0x473110ff).into()),
+ predictive: Some(rgba(0x40728bff).into()),
+ predictive_background: Some(rgba(0x1f210cff).into()),
+ predictive_border: Some(rgba(0x323610ff).into()),
+ renamed: Some(rgba(0x288bd1ff).into()),
+ renamed_background: Some(rgba(0x141f2cff).into()),
+ renamed_border: Some(rgba(0x1c3249ff).into()),
success: Some(rgba(0x859904ff).into()),
- success_background: Some(rgba(0xe9ead0ff).into()),
- success_border: Some(rgba(0xd6d9abff).into()),
- unreachable: Some(rgba(0x34555eff).into()),
- unreachable_background: Some(rgba(0xcfd0c4ff).into()),
- unreachable_border: Some(rgba(0x9faaa8ff).into()),
- warning: Some(rgba(0xb58904ff).into()),
- warning_background: Some(rgba(0xf5e6d0ff).into()),
- warning_border: Some(rgba(0xebd3aaff).into()),
+ success_background: Some(rgba(0x1f210cff).into()),
+ success_border: Some(rgba(0x323610ff).into()),
+ unreachable: Some(rgba(0x93a1a1ff).into()),
+ unreachable_background: Some(rgba(0x083743ff).into()),
+ unreachable_border: Some(rgba(0x2b4f58ff).into()),
+ warning: Some(rgba(0xb58903ff).into()),
+ warning_background: Some(rgba(0x2f1e0cff).into()),
+ warning_border: Some(rgba(0x473110ff).into()),
..Default::default()
},
player: Some(PlayerColors(vec![
PlayerColor {
- cursor: rgba(0x298bd1ff).into(),
- background: rgba(0x298bd1ff).into(),
- selection: rgba(0x298bd13d).into(),
+ cursor: rgba(0x288bd1ff).into(),
+ background: rgba(0x288bd1ff).into(),
+ selection: rgba(0x288bd13d).into(),
},
PlayerColor {
- cursor: rgba(0xd33882ff).into(),
- background: rgba(0xd33882ff).into(),
- selection: rgba(0xd338823d).into(),
+ cursor: rgba(0xd33782ff).into(),
+ background: rgba(0xd33782ff).into(),
+ selection: rgba(0xd337823d).into(),
},
PlayerColor {
- cursor: rgba(0xcb4c18ff).into(),
- background: rgba(0xcb4c18ff).into(),
- selection: rgba(0xcb4c183d).into(),
+ cursor: rgba(0xcb4b17ff).into(),
+ background: rgba(0xcb4b17ff).into(),
+ selection: rgba(0xcb4b173d).into(),
},
PlayerColor {
- cursor: rgba(0x6d71c4ff).into(),
- background: rgba(0x6d71c4ff).into(),
- selection: rgba(0x6d71c43d).into(),
+ cursor: rgba(0x6c71c4ff).into(),
+ background: rgba(0x6c71c4ff).into(),
+ selection: rgba(0x6c71c43d).into(),
},
PlayerColor {
cursor: rgba(0x2ca198ff).into(),
@@ -172,9 +172,9 @@ pub fn solarized() -> UserThemeFamily {
selection: rgba(0xdc33303d).into(),
},
PlayerColor {
- cursor: rgba(0xb58904ff).into(),
- background: rgba(0xb58904ff).into(),
- selection: rgba(0xb589043d).into(),
+ cursor: rgba(0xb58903ff).into(),
+ background: rgba(0xb58903ff).into(),
+ selection: rgba(0xb589033d).into(),
},
PlayerColor {
cursor: rgba(0x859904ff).into(),
@@ -187,7 +187,7 @@ pub fn solarized() -> UserThemeFamily {
(
"attribute".into(),
UserHighlightStyle {
- color: Some(rgba(0x298bd1ff).into()),
+ color: Some(rgba(0x288bd1ff).into()),
..Default::default()
},
),
@@ -201,14 +201,14 @@ pub fn solarized() -> UserThemeFamily {
(
"comment".into(),
UserHighlightStyle {
- color: Some(rgba(0x30525bff).into()),
+ color: Some(rgba(0x99a5a4ff).into()),
..Default::default()
},
),
(
"comment.doc".into(),
UserHighlightStyle {
- color: Some(rgba(0x30525bff).into()),
+ color: Some(rgba(0x99a5a4ff).into()),
..Default::default()
},
),
@@ -222,28 +222,28 @@ pub fn solarized() -> UserThemeFamily {
(
"constructor".into(),
UserHighlightStyle {
- color: Some(rgba(0x298bd1ff).into()),
+ color: Some(rgba(0x288bd1ff).into()),
..Default::default()
},
),
(
"embedded".into(),
UserHighlightStyle {
- color: Some(rgba(0x002b36ff).into()),
+ color: Some(rgba(0xfdf6e3ff).into()),
..Default::default()
},
),
(
"emphasis".into(),
UserHighlightStyle {
- color: Some(rgba(0x298bd1ff).into()),
+ color: Some(rgba(0x288bd1ff).into()),
..Default::default()
},
),
(
"emphasis.strong".into(),
UserHighlightStyle {
- color: Some(rgba(0x298bd1ff).into()),
+ color: Some(rgba(0x288bd1ff).into()),
font_weight: Some(UserFontWeight(700.0)),
..Default::default()
},
@@ -251,21 +251,21 @@ pub fn solarized() -> UserThemeFamily {
(
"enum".into(),
UserHighlightStyle {
- color: Some(rgba(0xcb4c18ff).into()),
+ color: Some(rgba(0xcb4b17ff).into()),
..Default::default()
},
),
(
"function".into(),
UserHighlightStyle {
- color: Some(rgba(0xb58904ff).into()),
+ color: Some(rgba(0xb58903ff).into()),
..Default::default()
},
),
(
"hint".into(),
UserHighlightStyle {
- color: Some(rgba(0x5889a3ff).into()),
+ color: Some(rgba(0x4f8297ff).into()),
font_weight: Some(UserFontWeight(700.0)),
..Default::default()
},
@@ -273,21 +273,21 @@ pub fn solarized() -> UserThemeFamily {
(
"keyword".into(),
UserHighlightStyle {
- color: Some(rgba(0x298bd1ff).into()),
+ color: Some(rgba(0x288bd1ff).into()),
..Default::default()
},
),
(
"label".into(),
UserHighlightStyle {
- color: Some(rgba(0x298bd1ff).into()),
+ color: Some(rgba(0x288bd1ff).into()),
..Default::default()
},
),
(
"link_text".into(),
UserHighlightStyle {
- color: Some(rgba(0xcb4c18ff).into()),
+ color: Some(rgba(0xcb4b17ff).into()),
font_style: Some(UserFontStyle::Italic),
..Default::default()
},
@@ -309,14 +309,14 @@ pub fn solarized() -> UserThemeFamily {
(
"operator".into(),
UserHighlightStyle {
- color: Some(rgba(0xcb4c18ff).into()),
+ color: Some(rgba(0xcb4b17ff).into()),
..Default::default()
},
),
(
"predictive".into(),
UserHighlightStyle {
- color: Some(rgba(0x679aafff).into()),
+ color: Some(rgba(0x40728bff).into()),
font_style: Some(UserFontStyle::Italic),
..Default::default()
},
@@ -324,112 +324,112 @@ pub fn solarized() -> UserThemeFamily {
(
"preproc".into(),
UserHighlightStyle {
- color: Some(rgba(0x002b36ff).into()),
+ color: Some(rgba(0xfdf6e3ff).into()),
..Default::default()
},
),
(
"primary".into(),
UserHighlightStyle {
- color: Some(rgba(0x002b36ff).into()),
+ color: Some(rgba(0xfdf6e3ff).into()),
..Default::default()
},
),
(
"property".into(),
UserHighlightStyle {
- color: Some(rgba(0x298bd1ff).into()),
+ color: Some(rgba(0x288bd1ff).into()),
..Default::default()
},
),
(
"punctuation".into(),
UserHighlightStyle {
- color: Some(rgba(0x05333eff).into()),
+ color: Some(rgba(0xefe9d6ff).into()),
..Default::default()
},
),
(
"punctuation.bracket".into(),
UserHighlightStyle {
- color: Some(rgba(0x05333eff).into()),
+ color: Some(rgba(0xefe9d6ff).into()),
..Default::default()
},
),
(
"punctuation.delimiter".into(),
UserHighlightStyle {
- color: Some(rgba(0x05333eff).into()),
+ color: Some(rgba(0xefe9d6ff).into()),
..Default::default()
},
),
(
"punctuation.list_marker".into(),
UserHighlightStyle {
- color: Some(rgba(0x05333eff).into()),
+ color: Some(rgba(0xefe9d6ff).into()),
..Default::default()
},
),
(
"punctuation.special".into(),
UserHighlightStyle {
- color: Some(rgba(0x05333eff).into()),
+ color: Some(rgba(0xefe9d6ff).into()),
..Default::default()
},
),
(
"string".into(),
UserHighlightStyle {
- color: Some(rgba(0xcb4c18ff).into()),
+ color: Some(rgba(0xcb4b17ff).into()),
..Default::default()
},
),
(
"string.escape".into(),
UserHighlightStyle {
- color: Some(rgba(0x30525bff).into()),
+ color: Some(rgba(0x99a5a4ff).into()),
..Default::default()
},
),
(
"string.regex".into(),
UserHighlightStyle {
- color: Some(rgba(0xcb4c18ff).into()),
+ color: Some(rgba(0xcb4b17ff).into()),
..Default::default()
},
),
(
"string.special".into(),
UserHighlightStyle {
- color: Some(rgba(0xcb4c18ff).into()),
+ color: Some(rgba(0xcb4b17ff).into()),
..Default::default()
},
),
(
"string.special.symbol".into(),
UserHighlightStyle {
- color: Some(rgba(0xcb4c18ff).into()),
+ color: Some(rgba(0xcb4b17ff).into()),
..Default::default()
},
),
(
"tag".into(),
UserHighlightStyle {
- color: Some(rgba(0x298bd1ff).into()),
+ color: Some(rgba(0x288bd1ff).into()),
..Default::default()
},
),
(
"text.literal".into(),
UserHighlightStyle {
- color: Some(rgba(0xcb4c18ff).into()),
+ color: Some(rgba(0xcb4b17ff).into()),
..Default::default()
},
),
(
"title".into(),
UserHighlightStyle {
- color: Some(rgba(0x002b36ff).into()),
+ color: Some(rgba(0xfdf6e3ff).into()),
font_weight: Some(UserFontWeight(700.0)),
..Default::default()
},
@@ -444,14 +444,14 @@ pub fn solarized() -> UserThemeFamily {
(
"variable".into(),
UserHighlightStyle {
- color: Some(rgba(0x002b36ff).into()),
+ color: Some(rgba(0xfdf6e3ff).into()),
..Default::default()
},
),
(
"variant".into(),
UserHighlightStyle {
- color: Some(rgba(0x298bd1ff).into()),
+ color: Some(rgba(0x288bd1ff).into()),
..Default::default()
},
),
@@ -460,150 +460,150 @@ pub fn solarized() -> UserThemeFamily {
},
},
UserTheme {
- name: "Solarized Dark".into(),
- appearance: Appearance::Dark,
+ name: "Solarized Light".into(),
+ appearance: Appearance::Light,
styles: UserThemeStylesRefinement {
colors: ThemeColorsRefinement {
- border: Some(rgba(0x2b4f58ff).into()),
- border_variant: Some(rgba(0x063541ff).into()),
- border_focused: Some(rgba(0x1c3249ff).into()),
- border_selected: Some(rgba(0x1c3249ff).into()),
+ border: Some(rgba(0x9faaa8ff).into()),
+ border_variant: Some(rgba(0xdcdacbff).into()),
+ border_focused: Some(rgba(0xbfd3efff).into()),
+ border_selected: Some(rgba(0xbfd3efff).into()),
border_transparent: Some(rgba(0x00000000).into()),
- border_disabled: Some(rgba(0x19424dff).into()),
- elevated_surface_background: Some(rgba(0x04313cff).into()),
- surface_background: Some(rgba(0x04313cff).into()),
- background: Some(rgba(0x083743ff).into()),
- panel_background: Some(rgba(0x04313cff).into()),
- element_background: Some(rgba(0x04313cff).into()),
- element_hover: Some(rgba(0x063541ff).into()),
- element_active: Some(rgba(0x294e58ff).into()),
- element_selected: Some(rgba(0x294e58ff).into()),
- element_disabled: Some(rgba(0x04313cff).into()),
- drop_target_background: Some(rgba(0x93a1a180).into()),
- ghost_element_background: Some(rgba(0x00000000).into()),
- ghost_element_hover: Some(rgba(0x063541ff).into()),
- ghost_element_active: Some(rgba(0x294e58ff).into()),
- ghost_element_selected: Some(rgba(0x294e58ff).into()),
- ghost_element_disabled: Some(rgba(0x04313cff).into()),
- text: Some(rgba(0xfdf6e3ff).into()),
- text_muted: Some(rgba(0x93a1a1ff).into()),
- text_placeholder: Some(rgba(0x6f8389ff).into()),
- text_disabled: Some(rgba(0x6f8389ff).into()),
- text_accent: Some(rgba(0x288bd1ff).into()),
- icon: Some(rgba(0xfdf6e3ff).into()),
- icon_muted: Some(rgba(0x93a1a1ff).into()),
- icon_disabled: Some(rgba(0x6f8389ff).into()),
- icon_placeholder: Some(rgba(0x93a1a1ff).into()),
- icon_accent: Some(rgba(0x288bd1ff).into()),
- status_bar_background: Some(rgba(0x083743ff).into()),
- title_bar_background: Some(rgba(0x083743ff).into()),
- toolbar_background: Some(rgba(0x002b36ff).into()),
- tab_bar_background: Some(rgba(0x04313cff).into()),
- tab_inactive_background: Some(rgba(0x04313cff).into()),
- tab_active_background: Some(rgba(0x002b36ff).into()),
- scrollbar_thumb_background: Some(rgba(0xfdf6e34c).into()),
- scrollbar_thumb_hover_background: Some(rgba(0x063541ff).into()),
- scrollbar_thumb_border: Some(rgba(0x063541ff).into()),
+ border_disabled: Some(rgba(0xb7bdb6ff).into()),
+ elevated_surface_background: Some(rgba(0xf3eddaff).into()),
+ surface_background: Some(rgba(0xf3eddaff).into()),
+ background: Some(rgba(0xcfd0c4ff).into()),
+ panel_background: Some(rgba(0xf3eddaff).into()),
+ element_background: Some(rgba(0xf3eddaff).into()),
+ element_hover: Some(rgba(0xdcdacbff).into()),
+ element_active: Some(rgba(0xa2aca9ff).into()),
+ element_selected: Some(rgba(0xa2aca9ff).into()),
+ element_disabled: Some(rgba(0xf3eddaff).into()),
+ drop_target_background: Some(rgba(0x34555e80).into()),
+ ghost_element_background: Some(rgba(0x00000000).into()),
+ ghost_element_hover: Some(rgba(0xdcdacbff).into()),
+ ghost_element_active: Some(rgba(0xa2aca9ff).into()),
+ ghost_element_selected: Some(rgba(0xa2aca9ff).into()),
+ ghost_element_disabled: Some(rgba(0xf3eddaff).into()),
+ text: Some(rgba(0x002b36ff).into()),
+ text_muted: Some(rgba(0x34555eff).into()),
+ text_placeholder: Some(rgba(0x6a7f86ff).into()),
+ text_disabled: Some(rgba(0x6a7f86ff).into()),
+ text_accent: Some(rgba(0x298bd1ff).into()),
+ icon: Some(rgba(0x002b36ff).into()),
+ icon_muted: Some(rgba(0x34555eff).into()),
+ icon_disabled: Some(rgba(0x6a7f86ff).into()),
+ icon_placeholder: Some(rgba(0x34555eff).into()),
+ icon_accent: Some(rgba(0x298bd1ff).into()),
+ status_bar_background: Some(rgba(0xcfd0c4ff).into()),
+ title_bar_background: Some(rgba(0xcfd0c4ff).into()),
+ toolbar_background: Some(rgba(0xfdf6e3ff).into()),
+ tab_bar_background: Some(rgba(0xf3eddaff).into()),
+ tab_inactive_background: Some(rgba(0xf3eddaff).into()),
+ tab_active_background: Some(rgba(0xfdf6e3ff).into()),
+ scrollbar_thumb_background: Some(rgba(0x002b364c).into()),
+ scrollbar_thumb_hover_background: Some(rgba(0xdcdacbff).into()),
+ scrollbar_thumb_border: Some(rgba(0xdcdacbff).into()),
scrollbar_track_background: Some(rgba(0x00000000).into()),
- scrollbar_track_border: Some(rgba(0x032f3bff).into()),
- editor_foreground: Some(rgba(0xfdf6e3ff).into()),
- editor_background: Some(rgba(0x002b36ff).into()),
- editor_gutter_background: Some(rgba(0x002b36ff).into()),
- editor_subheader_background: Some(rgba(0x04313cff).into()),
- editor_active_line_background: Some(rgba(0x04313cbf).into()),
- editor_highlighted_line_background: Some(rgba(0x04313cff).into()),
- editor_line_number: Some(rgba(0xfdf6e359).into()),
- editor_active_line_number: Some(rgba(0xfdf6e3ff).into()),
- editor_invisible: Some(rgba(0x93a1a1ff).into()),
- editor_wrap_guide: Some(rgba(0xfdf6e30d).into()),
- editor_active_wrap_guide: Some(rgba(0xfdf6e31a).into()),
- editor_document_highlight_read_background: Some(rgba(0x288bd11a).into()),
+ scrollbar_track_border: Some(rgba(0xf5eedbff).into()),
+ editor_foreground: Some(rgba(0x002b36ff).into()),
+ editor_background: Some(rgba(0xfdf6e3ff).into()),
+ editor_gutter_background: Some(rgba(0xfdf6e3ff).into()),
+ editor_subheader_background: Some(rgba(0xf3eddaff).into()),
+ editor_active_line_background: Some(rgba(0xf3eddabf).into()),
+ editor_highlighted_line_background: Some(rgba(0xf3eddaff).into()),
+ editor_line_number: Some(rgba(0x002b3659).into()),
+ editor_active_line_number: Some(rgba(0x002b36ff).into()),
+ editor_invisible: Some(rgba(0x34555eff).into()),
+ editor_wrap_guide: Some(rgba(0x002b360d).into()),
+ editor_active_wrap_guide: Some(rgba(0x002b361a).into()),
+ editor_document_highlight_read_background: Some(rgba(0x298bd11a).into()),
editor_document_highlight_write_background: Some(rgba(0x6d828866).into()),
- terminal_background: Some(rgba(0x002b36ff).into()),
- terminal_ansi_bright_black: Some(rgba(0x5c7279ff).into()),
- terminal_ansi_bright_red: Some(rgba(0x7d181cff).into()),
- terminal_ansi_bright_green: Some(rgba(0x434a11ff).into()),
- terminal_ansi_bright_yellow: Some(rgba(0x5d4310ff).into()),
- terminal_ansi_bright_blue: Some(rgba(0x214465ff).into()),
- terminal_ansi_bright_magenta: Some(rgba(0x6f1f40ff).into()),
- terminal_ansi_bright_cyan: Some(rgba(0x204e4aff).into()),
- terminal_ansi_bright_white: Some(rgba(0xfdf6e3ff).into()),
- terminal_ansi_black: Some(rgba(0x002b36ff).into()),
+ terminal_background: Some(rgba(0xfdf6e3ff).into()),
+ terminal_ansi_bright_black: Some(rgba(0x7b8e91ff).into()),
+ terminal_ansi_bright_red: Some(rgba(0xfaa091ff).into()),
+ terminal_ansi_bright_green: Some(rgba(0xc6cb8bff).into()),
+ terminal_ansi_bright_yellow: Some(rgba(0xe1c28aff).into()),
+ terminal_ansi_bright_blue: Some(rgba(0xa5c3e9ff).into()),
+ terminal_ansi_bright_magenta: Some(rgba(0xf0a2bfff).into()),
+ terminal_ansi_bright_cyan: Some(rgba(0x9fd0cbff).into()),
+ terminal_ansi_bright_white: Some(rgba(0x002b36ff).into()),
+ terminal_ansi_black: Some(rgba(0xfdf6e3ff).into()),
terminal_ansi_red: Some(rgba(0xdc3330ff).into()),
terminal_ansi_green: Some(rgba(0x859904ff).into()),
- terminal_ansi_yellow: Some(rgba(0xb58903ff).into()),
- terminal_ansi_blue: Some(rgba(0x288bd1ff).into()),
- terminal_ansi_magenta: Some(rgba(0xd33782ff).into()),
+ terminal_ansi_yellow: Some(rgba(0xb58904ff).into()),
+ terminal_ansi_blue: Some(rgba(0x298bd1ff).into()),
+ terminal_ansi_magenta: Some(rgba(0xd33882ff).into()),
terminal_ansi_cyan: Some(rgba(0x2ca198ff).into()),
- terminal_ansi_white: Some(rgba(0xfdf6e3ff).into()),
- link_text_hover: Some(rgba(0x288bd1ff).into()),
+ terminal_ansi_white: Some(rgba(0x002b36ff).into()),
+ link_text_hover: Some(rgba(0x298bd1ff).into()),
..Default::default()
},
status: StatusColorsRefinement {
- conflict: Some(rgba(0xb58903ff).into()),
- conflict_background: Some(rgba(0x2f1e0cff).into()),
- conflict_border: Some(rgba(0x473110ff).into()),
+ conflict: Some(rgba(0xb58904ff).into()),
+ conflict_background: Some(rgba(0xf5e6d0ff).into()),
+ conflict_border: Some(rgba(0xebd3aaff).into()),
created: Some(rgba(0x859904ff).into()),
- created_background: Some(rgba(0x1f210cff).into()),
- created_border: Some(rgba(0x323610ff).into()),
+ created_background: Some(rgba(0xe9ead0ff).into()),
+ created_border: Some(rgba(0xd6d9abff).into()),
deleted: Some(rgba(0xdc3330ff).into()),
- deleted_background: Some(rgba(0x4a090fff).into()),
- deleted_border: Some(rgba(0x641116ff).into()),
+ deleted_background: Some(rgba(0xffd9d2ff).into()),
+ deleted_border: Some(rgba(0xffbbafff).into()),
error: Some(rgba(0xdc3330ff).into()),
- error_background: Some(rgba(0x4a090fff).into()),
- error_border: Some(rgba(0x641116ff).into()),
- hidden: Some(rgba(0x6f8389ff).into()),
- hidden_background: Some(rgba(0x083743ff).into()),
- hidden_border: Some(rgba(0x19424dff).into()),
- hint: Some(rgba(0x4f8297ff).into()),
- hint_background: Some(rgba(0x141f2cff).into()),
- hint_border: Some(rgba(0x1c3249ff).into()),
- ignored: Some(rgba(0x93a1a1ff).into()),
- ignored_background: Some(rgba(0x083743ff).into()),
- ignored_border: Some(rgba(0x2b4f58ff).into()),
- info: Some(rgba(0x288bd1ff).into()),
- info_background: Some(rgba(0x141f2cff).into()),
- info_border: Some(rgba(0x1c3249ff).into()),
- modified: Some(rgba(0xb58903ff).into()),
- modified_background: Some(rgba(0x2f1e0cff).into()),
- modified_border: Some(rgba(0x473110ff).into()),
- predictive: Some(rgba(0x40728bff).into()),
- predictive_background: Some(rgba(0x1f210cff).into()),
- predictive_border: Some(rgba(0x323610ff).into()),
- renamed: Some(rgba(0x288bd1ff).into()),
- renamed_background: Some(rgba(0x141f2cff).into()),
- renamed_border: Some(rgba(0x1c3249ff).into()),
+ error_background: Some(rgba(0xffd9d2ff).into()),
+ error_border: Some(rgba(0xffbbafff).into()),
+ hidden: Some(rgba(0x6a7f86ff).into()),
+ hidden_background: Some(rgba(0xcfd0c4ff).into()),
+ hidden_border: Some(rgba(0xb7bdb6ff).into()),
+ hint: Some(rgba(0x5889a3ff).into()),
+ hint_background: Some(rgba(0xdbe6f6ff).into()),
+ hint_border: Some(rgba(0xbfd3efff).into()),
+ ignored: Some(rgba(0x34555eff).into()),
+ ignored_background: Some(rgba(0xcfd0c4ff).into()),
+ ignored_border: Some(rgba(0x9faaa8ff).into()),
+ info: Some(rgba(0x298bd1ff).into()),
+ info_background: Some(rgba(0xdbe6f6ff).into()),
+ info_border: Some(rgba(0xbfd3efff).into()),
+ modified: Some(rgba(0xb58904ff).into()),
+ modified_background: Some(rgba(0xf5e6d0ff).into()),
+ modified_border: Some(rgba(0xebd3aaff).into()),
+ predictive: Some(rgba(0x679aafff).into()),
+ predictive_background: Some(rgba(0xe9ead0ff).into()),
+ predictive_border: Some(rgba(0xd6d9abff).into()),
+ renamed: Some(rgba(0x298bd1ff).into()),
+ renamed_background: Some(rgba(0xdbe6f6ff).into()),
+ renamed_border: Some(rgba(0xbfd3efff).into()),
success: Some(rgba(0x859904ff).into()),
- success_background: Some(rgba(0x1f210cff).into()),
- success_border: Some(rgba(0x323610ff).into()),
- unreachable: Some(rgba(0x93a1a1ff).into()),
- unreachable_background: Some(rgba(0x083743ff).into()),
- unreachable_border: Some(rgba(0x2b4f58ff).into()),
- warning: Some(rgba(0xb58903ff).into()),
- warning_background: Some(rgba(0x2f1e0cff).into()),
- warning_border: Some(rgba(0x473110ff).into()),
+ success_background: Some(rgba(0xe9ead0ff).into()),
+ success_border: Some(rgba(0xd6d9abff).into()),
+ unreachable: Some(rgba(0x34555eff).into()),
+ unreachable_background: Some(rgba(0xcfd0c4ff).into()),
+ unreachable_border: Some(rgba(0x9faaa8ff).into()),
+ warning: Some(rgba(0xb58904ff).into()),
+ warning_background: Some(rgba(0xf5e6d0ff).into()),
+ warning_border: Some(rgba(0xebd3aaff).into()),
..Default::default()
},
player: Some(PlayerColors(vec![
PlayerColor {
- cursor: rgba(0x288bd1ff).into(),
- background: rgba(0x288bd1ff).into(),
- selection: rgba(0x288bd13d).into(),
+ cursor: rgba(0x298bd1ff).into(),
+ background: rgba(0x298bd1ff).into(),
+ selection: rgba(0x298bd13d).into(),
},
PlayerColor {
- cursor: rgba(0xd33782ff).into(),
- background: rgba(0xd33782ff).into(),
- selection: rgba(0xd337823d).into(),
+ cursor: rgba(0xd33882ff).into(),
+ background: rgba(0xd33882ff).into(),
+ selection: rgba(0xd338823d).into(),
},
PlayerColor {
- cursor: rgba(0xcb4b17ff).into(),
- background: rgba(0xcb4b17ff).into(),
- selection: rgba(0xcb4b173d).into(),
+ cursor: rgba(0xcb4c18ff).into(),
+ background: rgba(0xcb4c18ff).into(),
+ selection: rgba(0xcb4c183d).into(),
},
PlayerColor {
- cursor: rgba(0x6c71c4ff).into(),
- background: rgba(0x6c71c4ff).into(),
- selection: rgba(0x6c71c43d).into(),
+ cursor: rgba(0x6d71c4ff).into(),
+ background: rgba(0x6d71c4ff).into(),
+ selection: rgba(0x6d71c43d).into(),
},
PlayerColor {
cursor: rgba(0x2ca198ff).into(),
@@ -616,9 +616,9 @@ pub fn solarized() -> UserThemeFamily {
selection: rgba(0xdc33303d).into(),
},
PlayerColor {
- cursor: rgba(0xb58903ff).into(),
- background: rgba(0xb58903ff).into(),
- selection: rgba(0xb589033d).into(),
+ cursor: rgba(0xb58904ff).into(),
+ background: rgba(0xb58904ff).into(),
+ selection: rgba(0xb589043d).into(),
},
PlayerColor {
cursor: rgba(0x859904ff).into(),
@@ -631,7 +631,7 @@ pub fn solarized() -> UserThemeFamily {
(
"attribute".into(),
UserHighlightStyle {
- color: Some(rgba(0x288bd1ff).into()),
+ color: Some(rgba(0x298bd1ff).into()),
..Default::default()
},
),
@@ -645,14 +645,14 @@ pub fn solarized() -> UserThemeFamily {
(
"comment".into(),
UserHighlightStyle {
- color: Some(rgba(0x99a5a4ff).into()),
+ color: Some(rgba(0x30525bff).into()),
..Default::default()
},
),
(
"comment.doc".into(),
UserHighlightStyle {
- color: Some(rgba(0x99a5a4ff).into()),
+ color: Some(rgba(0x30525bff).into()),
..Default::default()
},
),
@@ -666,28 +666,28 @@ pub fn solarized() -> UserThemeFamily {
(
"constructor".into(),
UserHighlightStyle {
- color: Some(rgba(0x288bd1ff).into()),
+ color: Some(rgba(0x298bd1ff).into()),
..Default::default()
},
),
(
"embedded".into(),
UserHighlightStyle {
- color: Some(rgba(0xfdf6e3ff).into()),
+ color: Some(rgba(0x002b36ff).into()),
..Default::default()
},
),
(
"emphasis".into(),
UserHighlightStyle {
- color: Some(rgba(0x288bd1ff).into()),
+ color: Some(rgba(0x298bd1ff).into()),
..Default::default()
},
),
(
"emphasis.strong".into(),
UserHighlightStyle {
- color: Some(rgba(0x288bd1ff).into()),
+ color: Some(rgba(0x298bd1ff).into()),
font_weight: Some(UserFontWeight(700.0)),
..Default::default()
},
@@ -695,21 +695,21 @@ pub fn solarized() -> UserThemeFamily {
(
"enum".into(),
UserHighlightStyle {
- color: Some(rgba(0xcb4b17ff).into()),
+ color: Some(rgba(0xcb4c18ff).into()),
..Default::default()
},
),
(
"function".into(),
UserHighlightStyle {
- color: Some(rgba(0xb58903ff).into()),
+ color: Some(rgba(0xb58904ff).into()),
..Default::default()
},
),
(
"hint".into(),
UserHighlightStyle {
- color: Some(rgba(0x4f8297ff).into()),
+ color: Some(rgba(0x5889a3ff).into()),
font_weight: Some(UserFontWeight(700.0)),
..Default::default()
},
@@ -717,21 +717,21 @@ pub fn solarized() -> UserThemeFamily {
(
"keyword".into(),
UserHighlightStyle {
- color: Some(rgba(0x288bd1ff).into()),
+ color: Some(rgba(0x298bd1ff).into()),
..Default::default()
},
),
(
"label".into(),
UserHighlightStyle {
- color: Some(rgba(0x288bd1ff).into()),
+ color: Some(rgba(0x298bd1ff).into()),
..Default::default()
},
),
(
"link_text".into(),
UserHighlightStyle {
- color: Some(rgba(0xcb4b17ff).into()),
+ color: Some(rgba(0xcb4c18ff).into()),
font_style: Some(UserFontStyle::Italic),
..Default::default()
},
@@ -753,14 +753,14 @@ pub fn solarized() -> UserThemeFamily {
(
"operator".into(),
UserHighlightStyle {
- color: Some(rgba(0xcb4b17ff).into()),
+ color: Some(rgba(0xcb4c18ff).into()),
..Default::default()
},
),
(
"predictive".into(),
UserHighlightStyle {
- color: Some(rgba(0x40728bff).into()),
+ color: Some(rgba(0x679aafff).into()),
font_style: Some(UserFontStyle::Italic),
..Default::default()
},
@@ -768,112 +768,112 @@ pub fn solarized() -> UserThemeFamily {
(
"preproc".into(),
UserHighlightStyle {
- color: Some(rgba(0xfdf6e3ff).into()),
+ color: Some(rgba(0x002b36ff).into()),
..Default::default()
},
),
(
"primary".into(),
UserHighlightStyle {
- color: Some(rgba(0xfdf6e3ff).into()),
+ color: Some(rgba(0x002b36ff).into()),
..Default::default()
},
),
(
"property".into(),
UserHighlightStyle {
- color: Some(rgba(0x288bd1ff).into()),
+ color: Some(rgba(0x298bd1ff).into()),
..Default::default()
},
),
(
"punctuation".into(),
UserHighlightStyle {
- color: Some(rgba(0xefe9d6ff).into()),
+ color: Some(rgba(0x05333eff).into()),
..Default::default()
},
),
(
"punctuation.bracket".into(),
UserHighlightStyle {
- color: Some(rgba(0xefe9d6ff).into()),
+ color: Some(rgba(0x05333eff).into()),
..Default::default()
},
),
(
"punctuation.delimiter".into(),
UserHighlightStyle {
- color: Some(rgba(0xefe9d6ff).into()),
+ color: Some(rgba(0x05333eff).into()),
..Default::default()
},
),
(
"punctuation.list_marker".into(),
UserHighlightStyle {
- color: Some(rgba(0xefe9d6ff).into()),
+ color: Some(rgba(0x05333eff).into()),
..Default::default()
},
),
(
"punctuation.special".into(),
UserHighlightStyle {
- color: Some(rgba(0xefe9d6ff).into()),
+ color: Some(rgba(0x05333eff).into()),
..Default::default()
},
),
(
"string".into(),
UserHighlightStyle {
- color: Some(rgba(0xcb4b17ff).into()),
+ color: Some(rgba(0xcb4c18ff).into()),
..Default::default()
},
),
(
"string.escape".into(),
UserHighlightStyle {
- color: Some(rgba(0x99a5a4ff).into()),
+ color: Some(rgba(0x30525bff).into()),
..Default::default()
},
),
(
"string.regex".into(),
UserHighlightStyle {
- color: Some(rgba(0xcb4b17ff).into()),
+ color: Some(rgba(0xcb4c18ff).into()),
..Default::default()
},
),
(
"string.special".into(),
UserHighlightStyle {
- color: Some(rgba(0xcb4b17ff).into()),
+ color: Some(rgba(0xcb4c18ff).into()),
..Default::default()
},
),
(
"string.special.symbol".into(),
UserHighlightStyle {
- color: Some(rgba(0xcb4b17ff).into()),
+ color: Some(rgba(0xcb4c18ff).into()),
..Default::default()
},
),
(
"tag".into(),
UserHighlightStyle {
- color: Some(rgba(0x288bd1ff).into()),
+ color: Some(rgba(0x298bd1ff).into()),
..Default::default()
},
),
(
"text.literal".into(),
UserHighlightStyle {
- color: Some(rgba(0xcb4b17ff).into()),
+ color: Some(rgba(0xcb4c18ff).into()),
..Default::default()
},
),
(
"title".into(),
UserHighlightStyle {
- color: Some(rgba(0xfdf6e3ff).into()),
+ color: Some(rgba(0x002b36ff).into()),
font_weight: Some(UserFontWeight(700.0)),
..Default::default()
},
@@ -11,6 +11,7 @@ clap = { version = "4.4", features = ["derive"] }
convert_case = "0.6.0"
gpui = { path = "../gpui" }
indexmap = { version = "1.6.2", features = ["serde"] }
+indoc.workspace = true
json_comments = "0.2.2"
log.workspace = true
palette = { version = "0.7.3", default-features = false, features = ["std"] }
@@ -18,6 +18,7 @@ use clap::Parser;
use convert_case::{Case, Casing};
use gpui::serde_json;
use indexmap::IndexMap;
+use indoc::formatdoc;
use json_comments::StripComments;
use log::LevelFilter;
use serde::Deserialize;
@@ -28,7 +29,7 @@ use crate::theme_printer::UserThemeFamilyPrinter;
use crate::vscode::VsCodeTheme;
use crate::vscode::VsCodeThemeConverter;
use crate::zed1::theme::Theme as Zed1Theme;
-use crate::zed1::Zed1ThemeConverter;
+use crate::zed1::{zed1_theme_licenses, Zed1ThemeConverter};
#[derive(Debug, Deserialize)]
struct FamilyMetadata {
@@ -200,7 +201,13 @@ fn main() -> Result<()> {
"Summercamp",
];
- let mut zed1_themes_by_family: HashMap<String, Vec<UserTheme>> = HashMap::from_iter(
+ let zed1_licenses_by_theme: HashMap<String, zed1::Zed1ThemeLicense> = HashMap::from_iter(
+ zed1_theme_licenses()
+ .into_iter()
+ .map(|theme_license| (theme_license.theme.clone(), theme_license)),
+ );
+
+ let mut zed1_themes_by_family: IndexMap<String, Vec<UserTheme>> = IndexMap::from_iter(
zed1_theme_familes
.into_iter()
.map(|family| (family.to_string(), Vec::new())),
@@ -254,13 +261,44 @@ fn main() -> Result<()> {
themes_for_family.push(theme);
}
+ zed1_themes_by_family.sort_keys();
+
+ let mut licenses = Vec::new();
+
for (family, themes) in zed1_themes_by_family {
- let theme_family = UserThemeFamily {
+ let mut theme_family = UserThemeFamily {
name: family,
author: "Zed Industries".to_string(),
themes,
};
+ theme_family
+ .themes
+ .sort_unstable_by_key(|theme| theme.name.clone());
+
+ for theme in &theme_family.themes {
+ let license = zed1_licenses_by_theme
+ .get(&theme.name)
+ .ok_or_else(|| anyhow!("missing license for theme: '{}'", theme.name))?;
+
+ let license_header = match license.license_url.as_ref() {
+ Some(license_url) => {
+ format!("[{theme_name}]({license_url})", theme_name = theme.name)
+ }
+ None => theme.name.clone(),
+ };
+
+ licenses.push(formatdoc!(
+ "
+ ## {license_header}
+
+ {license_text}
+ ********************************************************************************
+ ",
+ license_text = license.license_text
+ ));
+ }
+
theme_families.push(theme_family);
}
@@ -357,6 +395,12 @@ fn main() -> Result<()> {
mod_rs_file.write_all(mod_rs_contents.as_bytes())?;
+ log::info!("Writing LICENSES file...");
+
+ let mut licenses_file = File::create(themes_output_path.join(format!("LICENSES")))?;
+
+ licenses_file.write_all(licenses.join("\n").as_bytes())?;
+
log::info!("Formatting themes...");
let format_result = format_themes_crate()
@@ -1,4 +1,6 @@
mod converter;
+mod licenses;
pub mod theme;
pub use converter::*;
+pub use licenses::*;
@@ -0,0 +1,1192 @@
+use std::fmt::Display;
+
+use indoc::indoc;
+
+#[derive(Debug)]
+pub enum License {
+ Mit,
+ // We don't currently have any themes using the Apache 2.0 license.
+ #[allow(unused)]
+ Apache2,
+}
+
+impl Display for License {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ write!(
+ f,
+ "{}",
+ match self {
+ License::Mit => "MIT",
+ License::Apache2 => "Apache License 2.0",
+ }
+ )
+ }
+}
+
+pub struct Zed1ThemeLicense {
+ pub theme: String,
+ pub license: License,
+ pub license_url: Option<String>,
+ pub license_text: &'static str,
+}
+
+pub fn zed1_theme_licenses() -> Vec<Zed1ThemeLicense> {
+ vec![
+ Zed1ThemeLicense {
+ theme: "One Dark".to_string(),
+ license: License::Mit,
+ license_url: Some(
+ "https://github.com/atom/atom/tree/master/packages/one-dark-ui".to_string(),
+ ),
+ license_text: indoc! {r#"
+ The MIT License (MIT)
+
+ Copyright (c) 2014 GitHub Inc.
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+ "#},
+ },
+ Zed1ThemeLicense {
+ theme: "One Light".to_string(),
+ license: License::Mit,
+ license_url: Some(
+ "https://github.com/atom/atom/tree/master/packages/one-light-ui".to_string(),
+ ),
+ license_text: indoc! {r#"
+ The MIT License (MIT)
+
+ Copyright (c) 2014 GitHub Inc.
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+ "#},
+ },
+ Zed1ThemeLicense {
+ theme: "Ayu Light".to_string(),
+ license: License::Mit,
+ license_url: Some("https://github.com/dempfi/ayu".to_string()),
+ license_text: indoc! {r#"
+ The MIT License (MIT)
+
+ Copyright (c) 2016 Ike Ku
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+ "#},
+ },
+ Zed1ThemeLicense {
+ theme: "Ayu Dark".to_string(),
+ license: License::Mit,
+ license_url: Some("https://github.com/dempfi/ayu".to_string()),
+ license_text: indoc! {r#"
+ The MIT License (MIT)
+
+ Copyright (c) 2016 Ike Ku
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+ "#},
+ },
+ Zed1ThemeLicense {
+ theme: "Ayu Mirage".to_string(),
+ license: License::Mit,
+ license_url: Some("https://github.com/dempfi/ayu".to_string()),
+ license_text: indoc! {r#"
+ The MIT License (MIT)
+
+ Copyright (c) 2016 Ike Ku
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+ "#},
+ },
+ Zed1ThemeLicense {
+ theme: "Gruvbox Dark".to_string(),
+ license: License::Mit,
+ license_url: Some("https://github.com/morhetz/gruvbox".to_string()),
+ license_text: indoc! {r#"
+ The MIT License (MIT)
+
+ Copyright (c) <YEAR> <COPYRIGHT HOLDER>
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+ "#},
+ },
+ Zed1ThemeLicense {
+ theme: "Gruvbox Dark Hard".to_string(),
+ license: License::Mit,
+ license_url: Some("https://github.com/morhetz/gruvbox".to_string()),
+ license_text: indoc! {r#"
+ The MIT License (MIT)
+
+ Copyright (c) <YEAR> <COPYRIGHT HOLDER>
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+ "#},
+ },
+ Zed1ThemeLicense {
+ theme: "Gruvbox Dark Soft".to_string(),
+ license: License::Mit,
+ license_url: Some("https://github.com/morhetz/gruvbox".to_string()),
+ license_text: indoc! {r#"
+ The MIT License (MIT)
+
+ Copyright (c) <YEAR> <COPYRIGHT HOLDER>
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+ "#},
+ },
+ Zed1ThemeLicense {
+ theme: "Gruvbox Light".to_string(),
+ license: License::Mit,
+ license_url: Some("https://github.com/morhetz/gruvbox".to_string()),
+ license_text: indoc! {r#"
+ The MIT License (MIT)
+
+ Copyright (c) <YEAR> <COPYRIGHT HOLDER>
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+ "#},
+ },
+ Zed1ThemeLicense {
+ theme: "Gruvbox Light Hard".to_string(),
+ license: License::Mit,
+ license_url: Some("https://github.com/morhetz/gruvbox".to_string()),
+ license_text: indoc! {r#"
+ The MIT License (MIT)
+
+ Copyright (c) <YEAR> <COPYRIGHT HOLDER>
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+ "#},
+ },
+ Zed1ThemeLicense {
+ theme: "Gruvbox Light Soft".to_string(),
+ license: License::Mit,
+ license_url: Some("https://github.com/morhetz/gruvbox".to_string()),
+ license_text: indoc! {r#"
+ The MIT License (MIT)
+
+ Copyright (c) <YEAR> <COPYRIGHT HOLDER>
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+ "#},
+ },
+ Zed1ThemeLicense {
+ theme: "Rosé Pine".to_string(),
+ license: License::Mit,
+ license_url: Some("https://github.com/edunfelt/base16-rose-pine-scheme".to_string()),
+ license_text: indoc! {r#"
+ The MIT License (MIT)
+
+ Copyright (c) 2021 Emilia Dunfelt
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+ "#},
+ },
+ Zed1ThemeLicense {
+ theme: "Rosé Pine Dawn".to_string(),
+ license: License::Mit,
+ license_url: Some("https://github.com/edunfelt/base16-rose-pine-scheme".to_string()),
+ license_text: indoc! {r#"
+ The MIT License (MIT)
+
+ Copyright (c) 2021 Emilia Dunfelt
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+ "#},
+ },
+ Zed1ThemeLicense {
+ theme: "Rosé Pine Moon".to_string(),
+ license: License::Mit,
+ license_url: Some("https://github.com/edunfelt/base16-rose-pine-scheme".to_string()),
+ license_text: indoc! {r#"
+ The MIT License (MIT)
+
+ Copyright (c) 2021 Emilia Dunfelt
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+ "#},
+ },
+ Zed1ThemeLicense {
+ theme: "Sandcastle".to_string(),
+ license: License::Mit,
+ license_url: Some("https://github.com/gessig/base16-sandcastle-scheme".to_string()),
+ license_text: indoc! {r#"
+ The MIT License (MIT)
+
+ Copyright (c) 2019 George Essig
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+ "#},
+ },
+ Zed1ThemeLicense {
+ theme: "Solarized Dark".to_string(),
+ license: License::Mit,
+ license_url: Some("https://github.com/altercation/solarized".to_string()),
+ license_text: indoc! {r#"
+ The MIT License (MIT)
+
+ Copyright (c) 2011 Ethan Schoonover
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+ "#},
+ },
+ Zed1ThemeLicense {
+ theme: "Solarized Light".to_string(),
+ license: License::Mit,
+ license_url: Some("https://github.com/altercation/solarized".to_string()),
+ license_text: indoc! {r#"
+ The MIT License (MIT)
+
+ Copyright (c) 2011 Ethan Schoonover
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+ "#},
+ },
+ Zed1ThemeLicense {
+ theme: "Andromeda".to_string(),
+ license: License::Mit,
+ license_url: Some("https://github.com/EliverLara/Andromeda".to_string()),
+ license_text: indoc! {r#"
+ The MIT License (MIT)
+
+ Copyright (c) 2017 <eliverlara@gmail.com>
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+ "#},
+ },
+ Zed1ThemeLicense {
+ theme: "Summercamp".to_string(),
+ license: License::Mit,
+ license_url: Some("https://github.com/zoefiri/base16-sc".to_string()),
+ license_text: indoc! {r#"
+ The MIT License (MIT)
+
+ Copyright (c) 2019 Zoe FiriH
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+ "#},
+ },
+ Zed1ThemeLicense {
+ theme: "Atelier Cave Dark".to_string(),
+ license: License::Mit,
+ license_url: Some(
+ "https://atelierbram.github.io/syntax-highlighting/atelier-schemes/cave/"
+ .to_string(),
+ ),
+ license_text: indoc! {r#"
+ The MIT License (MIT)
+
+ Copyright (c) 2023 Bram de Haan, http://atelierbramdehaan.nl
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+ "#},
+ },
+ Zed1ThemeLicense {
+ theme: "Atelier Cave Light".to_string(),
+ license: License::Mit,
+ license_url: Some(
+ "https://atelierbram.github.io/syntax-highlighting/atelier-schemes/cave/"
+ .to_string(),
+ ),
+ license_text: indoc! {r#"
+ The MIT License (MIT)
+
+ Copyright (c) 2023 Bram de Haan, http://atelierbramdehaan.nl
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+ "#},
+ },
+ Zed1ThemeLicense {
+ theme: "Atelier Dune Dark".to_string(),
+ license: License::Mit,
+ license_url: Some(
+ "https://atelierbram.github.io/syntax-highlighting/atelier-schemes/cave/"
+ .to_string(),
+ ),
+ license_text: indoc! {r#"
+ The MIT License (MIT)
+
+ Copyright (c) 2023 Bram de Haan, http://atelierbramdehaan.nl
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+ "#},
+ },
+ Zed1ThemeLicense {
+ theme: "Atelier Dune Light".to_string(),
+ license: License::Mit,
+ license_url: Some(
+ "https://atelierbram.github.io/syntax-highlighting/atelier-schemes/cave/"
+ .to_string(),
+ ),
+ license_text: indoc! {r#"
+ The MIT License (MIT)
+
+ Copyright (c) 2023 Bram de Haan, http://atelierbramdehaan.nl
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+ "#},
+ },
+ Zed1ThemeLicense {
+ theme: "Atelier Estuary Dark".to_string(),
+ license: License::Mit,
+ license_url: Some(
+ "https://atelierbram.github.io/syntax-highlighting/atelier-schemes/cave/"
+ .to_string(),
+ ),
+ license_text: indoc! {r#"
+ The MIT License (MIT)
+
+ Copyright (c) 2023 Bram de Haan, http://atelierbramdehaan.nl
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+ "#},
+ },
+ Zed1ThemeLicense {
+ theme: "Atelier Estuary Light".to_string(),
+ license: License::Mit,
+ license_url: Some(
+ "https://atelierbram.github.io/syntax-highlighting/atelier-schemes/cave/"
+ .to_string(),
+ ),
+ license_text: indoc! {r#"
+ The MIT License (MIT)
+
+ Copyright (c) 2023 Bram de Haan, http://atelierbramdehaan.nl
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+ "#},
+ },
+ Zed1ThemeLicense {
+ theme: "Atelier Forest Dark".to_string(),
+ license: License::Mit,
+ license_url: Some(
+ "https://atelierbram.github.io/syntax-highlighting/atelier-schemes/cave/"
+ .to_string(),
+ ),
+ license_text: indoc! {r#"
+ The MIT License (MIT)
+
+ Copyright (c) 2023 Bram de Haan, http://atelierbramdehaan.nl
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+ "#},
+ },
+ Zed1ThemeLicense {
+ theme: "Atelier Forest Light".to_string(),
+ license: License::Mit,
+ license_url: Some(
+ "https://atelierbram.github.io/syntax-highlighting/atelier-schemes/cave/"
+ .to_string(),
+ ),
+ license_text: indoc! {r#"
+ The MIT License (MIT)
+
+ Copyright (c) 2023 Bram de Haan, http://atelierbramdehaan.nl
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+ "#},
+ },
+ Zed1ThemeLicense {
+ theme: "Atelier Heath Dark".to_string(),
+ license: License::Mit,
+ license_url: Some(
+ "https://atelierbram.github.io/syntax-highlighting/atelier-schemes/cave/"
+ .to_string(),
+ ),
+ license_text: indoc! {r#"
+ The MIT License (MIT)
+
+ Copyright (c) 2023 Bram de Haan, http://atelierbramdehaan.nl
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+ "#},
+ },
+ Zed1ThemeLicense {
+ theme: "Atelier Heath Light".to_string(),
+ license: License::Mit,
+ license_url: Some(
+ "https://atelierbram.github.io/syntax-highlighting/atelier-schemes/cave/"
+ .to_string(),
+ ),
+ license_text: indoc! {r#"
+ The MIT License (MIT)
+
+ Copyright (c) 2023 Bram de Haan, http://atelierbramdehaan.nl
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+ "#},
+ },
+ Zed1ThemeLicense {
+ theme: "Atelier Lakeside Dark".to_string(),
+ license: License::Mit,
+ license_url: Some(
+ "https://atelierbram.github.io/syntax-highlighting/atelier-schemes/cave/"
+ .to_string(),
+ ),
+ license_text: indoc! {r#"
+ The MIT License (MIT)
+
+ Copyright (c) 2023 Bram de Haan, http://atelierbramdehaan.nl
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+ "#},
+ },
+ Zed1ThemeLicense {
+ theme: "Atelier Lakeside Light".to_string(),
+ license: License::Mit,
+ license_url: Some(
+ "https://atelierbram.github.io/syntax-highlighting/atelier-schemes/cave/"
+ .to_string(),
+ ),
+ license_text: indoc! {r#"
+ The MIT License (MIT)
+
+ Copyright (c) 2023 Bram de Haan, http://atelierbramdehaan.nl
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+ "#},
+ },
+ Zed1ThemeLicense {
+ theme: "Atelier Plateau Dark".to_string(),
+ license: License::Mit,
+ license_url: Some(
+ "https://atelierbram.github.io/syntax-highlighting/atelier-schemes/cave/"
+ .to_string(),
+ ),
+ license_text: indoc! {r#"
+ The MIT License (MIT)
+
+ Copyright (c) 2023 Bram de Haan, http://atelierbramdehaan.nl
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+ "#},
+ },
+ Zed1ThemeLicense {
+ theme: "Atelier Plateau Light".to_string(),
+ license: License::Mit,
+ license_url: Some(
+ "https://atelierbram.github.io/syntax-highlighting/atelier-schemes/cave/"
+ .to_string(),
+ ),
+ license_text: indoc! {r#"
+ The MIT License (MIT)
+
+ Copyright (c) 2023 Bram de Haan, http://atelierbramdehaan.nl
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+ "#},
+ },
+ Zed1ThemeLicense {
+ theme: "Atelier Savanna Dark".to_string(),
+ license: License::Mit,
+ license_url: Some(
+ "https://atelierbram.github.io/syntax-highlighting/atelier-schemes/cave/"
+ .to_string(),
+ ),
+ license_text: indoc! {r#"
+ The MIT License (MIT)
+
+ Copyright (c) 2023 Bram de Haan, http://atelierbramdehaan.nl
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+ "#},
+ },
+ Zed1ThemeLicense {
+ theme: "Atelier Savanna Light".to_string(),
+ license: License::Mit,
+ license_url: Some(
+ "https://atelierbram.github.io/syntax-highlighting/atelier-schemes/cave/"
+ .to_string(),
+ ),
+ license_text: indoc! {r#"
+ The MIT License (MIT)
+
+ Copyright (c) 2023 Bram de Haan, http://atelierbramdehaan.nl
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+ "#},
+ },
+ Zed1ThemeLicense {
+ theme: "Atelier Seaside Dark".to_string(),
+ license: License::Mit,
+ license_url: Some(
+ "https://atelierbram.github.io/syntax-highlighting/atelier-schemes/cave/"
+ .to_string(),
+ ),
+ license_text: indoc! {r#"
+ The MIT License (MIT)
+
+ Copyright (c) 2023 Bram de Haan, http://atelierbramdehaan.nl
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+ "#},
+ },
+ Zed1ThemeLicense {
+ theme: "Atelier Seaside Light".to_string(),
+ license: License::Mit,
+ license_url: Some(
+ "https://atelierbram.github.io/syntax-highlighting/atelier-schemes/cave/"
+ .to_string(),
+ ),
+ license_text: indoc! {r#"
+ The MIT License (MIT)
+
+ Copyright (c) 2023 Bram de Haan, http://atelierbramdehaan.nl
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+ "#},
+ },
+ Zed1ThemeLicense {
+ theme: "Atelier Sulphurpool Dark".to_string(),
+ license: License::Mit,
+ license_url: Some(
+ "https://atelierbram.github.io/syntax-highlighting/atelier-schemes/cave/"
+ .to_string(),
+ ),
+ license_text: indoc! {r#"
+ The MIT License (MIT)
+
+ Copyright (c) 2023 Bram de Haan, http://atelierbramdehaan.nl
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+ "#},
+ },
+ Zed1ThemeLicense {
+ theme: "Atelier Sulphurpool Light".to_string(),
+ license: License::Mit,
+ license_url: Some(
+ "https://atelierbram.github.io/syntax-highlighting/atelier-schemes/cave/"
+ .to_string(),
+ ),
+ license_text: indoc! {r#"
+ The MIT License (MIT)
+
+ Copyright (c) 2023 Bram de Haan, http://atelierbramdehaan.nl
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+ "#},
+ },
+ ]
+}
@@ -92,6 +92,13 @@ impl Selectable for Button {
}
}
+impl SelectableButton for Button {
+ fn selected_style(mut self, style: ButtonStyle) -> Self {
+ self.base = self.base.selected_style(style);
+ self
+ }
+}
+
impl Disableable for Button {
fn disabled(mut self, disabled: bool) -> Self {
self.base = self.base.disabled(disabled);
@@ -12,6 +12,7 @@ pub(super) struct ButtonIcon {
disabled: bool,
selected: bool,
selected_icon: Option<Icon>,
+ selected_style: Option<ButtonStyle>,
}
impl ButtonIcon {
@@ -23,6 +24,7 @@ impl ButtonIcon {
disabled: false,
selected: false,
selected_icon: None,
+ selected_style: None,
}
}
@@ -62,6 +64,13 @@ impl Selectable for ButtonIcon {
}
}
+impl SelectableButton for ButtonIcon {
+ fn selected_style(mut self, style: ButtonStyle) -> Self {
+ self.selected_style = Some(style);
+ self
+ }
+}
+
impl RenderOnce for ButtonIcon {
fn render(self, _cx: &mut WindowContext) -> impl IntoElement {
let icon = self
@@ -71,6 +80,8 @@ impl RenderOnce for ButtonIcon {
let icon_color = if self.disabled {
Color::Disabled
+ } else if self.selected_style.is_some() && self.selected {
+ self.selected_style.unwrap().into()
} else if self.selected {
Color::Selected
} else {
@@ -4,6 +4,10 @@ use smallvec::SmallVec;
use crate::prelude::*;
+pub trait SelectableButton: Selectable {
+ fn selected_style(self, style: ButtonStyle) -> Self;
+}
+
pub trait ButtonCommon: Clickable + Disableable {
/// A unique element ID to identify the button.
fn id(&self) -> &ElementId;
@@ -36,17 +40,68 @@ pub enum IconPosition {
End,
}
+#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Default)]
+pub enum TintColor {
+ #[default]
+ Accent,
+ Negative,
+ Warning,
+}
+
+impl TintColor {
+ fn button_like_style(self, cx: &mut WindowContext) -> ButtonLikeStyles {
+ match self {
+ TintColor::Accent => ButtonLikeStyles {
+ background: cx.theme().status().info_background,
+ border_color: cx.theme().status().info_border,
+ label_color: cx.theme().colors().text,
+ icon_color: cx.theme().colors().text,
+ },
+ TintColor::Negative => ButtonLikeStyles {
+ background: cx.theme().status().error_background,
+ border_color: cx.theme().status().error_border,
+ label_color: cx.theme().colors().text,
+ icon_color: cx.theme().colors().text,
+ },
+ TintColor::Warning => ButtonLikeStyles {
+ background: cx.theme().status().warning_background,
+ border_color: cx.theme().status().warning_border,
+ label_color: cx.theme().colors().text,
+ icon_color: cx.theme().colors().text,
+ },
+ }
+ }
+}
+
+impl From<TintColor> for Color {
+ fn from(tint: TintColor) -> Self {
+ match tint {
+ TintColor::Accent => Color::Accent,
+ TintColor::Negative => Color::Error,
+ TintColor::Warning => Color::Warning,
+ }
+ }
+}
+
+// Used to go from ButtonStyle -> Color through tint colors.
+impl From<ButtonStyle> for Color {
+ fn from(style: ButtonStyle) -> Self {
+ match style {
+ ButtonStyle::Tinted(tint) => tint.into(),
+ _ => Color::Default,
+ }
+ }
+}
+
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Default)]
pub enum ButtonStyle {
/// A filled button with a solid background color. Provides emphasis versus
/// the more common subtle button.
Filled,
- /// 🚧 Under construction 🚧
- ///
/// Used to emphasize a button in some way, like a selected state, or a semantic
/// coloring like an error or success button.
- Tinted,
+ Tinted(TintColor),
/// The default button style, used for most buttons. Has a transparent background,
/// but has a background color to indicate states like hover and active.
@@ -86,12 +141,7 @@ impl ButtonStyle {
label_color: Color::Default.color(cx),
icon_color: Color::Default.color(cx),
},
- ButtonStyle::Tinted => ButtonLikeStyles {
- background: gpui::red(),
- border_color: gpui::red(),
- label_color: gpui::red(),
- icon_color: gpui::red(),
- },
+ ButtonStyle::Tinted(tint) => tint.button_like_style(cx),
ButtonStyle::Subtle => ButtonLikeStyles {
background: cx.theme().colors().ghost_element_background,
border_color: transparent_black(),
@@ -115,12 +165,7 @@ impl ButtonStyle {
label_color: Color::Default.color(cx),
icon_color: Color::Default.color(cx),
},
- ButtonStyle::Tinted => ButtonLikeStyles {
- background: gpui::red(),
- border_color: gpui::red(),
- label_color: gpui::red(),
- icon_color: gpui::red(),
- },
+ ButtonStyle::Tinted(tint) => tint.button_like_style(cx),
ButtonStyle::Subtle => ButtonLikeStyles {
background: cx.theme().colors().ghost_element_hover,
border_color: transparent_black(),
@@ -146,12 +191,7 @@ impl ButtonStyle {
label_color: Color::Default.color(cx),
icon_color: Color::Default.color(cx),
},
- ButtonStyle::Tinted => ButtonLikeStyles {
- background: gpui::red(),
- border_color: gpui::red(),
- label_color: gpui::red(),
- icon_color: gpui::red(),
- },
+ ButtonStyle::Tinted(tint) => tint.button_like_style(cx),
ButtonStyle::Subtle => ButtonLikeStyles {
background: cx.theme().colors().ghost_element_active,
border_color: transparent_black(),
@@ -178,12 +218,7 @@ impl ButtonStyle {
label_color: Color::Default.color(cx),
icon_color: Color::Default.color(cx),
},
- ButtonStyle::Tinted => ButtonLikeStyles {
- background: gpui::red(),
- border_color: gpui::red(),
- label_color: gpui::red(),
- icon_color: gpui::red(),
- },
+ ButtonStyle::Tinted(tint) => tint.button_like_style(cx),
ButtonStyle::Subtle => ButtonLikeStyles {
background: cx.theme().colors().ghost_element_background,
border_color: cx.theme().colors().border_focused,
@@ -208,12 +243,7 @@ impl ButtonStyle {
label_color: Color::Disabled.color(cx),
icon_color: Color::Disabled.color(cx),
},
- ButtonStyle::Tinted => ButtonLikeStyles {
- background: gpui::red(),
- border_color: gpui::red(),
- label_color: gpui::red(),
- icon_color: gpui::red(),
- },
+ ButtonStyle::Tinted(tint) => tint.button_like_style(cx),
ButtonStyle::Subtle => ButtonLikeStyles {
background: cx.theme().colors().ghost_element_disabled,
border_color: cx.theme().colors().border_disabled,
@@ -264,6 +294,7 @@ pub struct ButtonLike {
pub(super) style: ButtonStyle,
pub(super) disabled: bool,
pub(super) selected: bool,
+ pub(super) selected_style: Option<ButtonStyle>,
pub(super) width: Option<DefiniteLength>,
size: ButtonSize,
rounding: Option<ButtonLikeRounding>,
@@ -280,6 +311,7 @@ impl ButtonLike {
style: ButtonStyle::default(),
disabled: false,
selected: false,
+ selected_style: None,
width: None,
size: ButtonSize::Default,
rounding: Some(ButtonLikeRounding::All),
@@ -309,6 +341,13 @@ impl Selectable for ButtonLike {
}
}
+impl SelectableButton for ButtonLike {
+ fn selected_style(mut self, style: ButtonStyle) -> Self {
+ self.selected_style = Some(style);
+ self
+ }
+}
+
impl Clickable for ButtonLike {
fn on_click(mut self, handler: impl Fn(&ClickEvent, &mut WindowContext) + 'static) -> Self {
self.on_click = Some(Box::new(handler));
@@ -364,6 +403,11 @@ impl ParentElement for ButtonLike {
impl RenderOnce for ButtonLike {
fn render(self, cx: &mut WindowContext) -> impl IntoElement {
+ let style = self
+ .selected_style
+ .filter(|_| self.selected)
+ .unwrap_or(self.style);
+
self.base
.h_flex()
.id(self.id.clone())
@@ -382,12 +426,12 @@ impl RenderOnce for ButtonLike {
ButtonSize::Default | ButtonSize::Compact => this.px_1(),
ButtonSize::None => this,
})
- .bg(self.style.enabled(cx).background)
+ .bg(style.enabled(cx).background)
.when(self.disabled, |this| this.cursor_not_allowed())
.when(!self.disabled, |this| {
this.cursor_pointer()
- .hover(|hover| hover.bg(self.style.hovered(cx).background))
- .active(|active| active.bg(self.style.active(cx).background))
+ .hover(|hover| hover.bg(style.hovered(cx).background))
+ .active(|active| active.bg(style.active(cx).background))
})
.when_some(
self.on_click.filter(|_| !self.disabled),
@@ -1,6 +1,6 @@
use gpui::{AnyView, DefiniteLength};
-use crate::prelude::*;
+use crate::{prelude::*, SelectableButton};
use crate::{ButtonCommon, ButtonLike, ButtonSize, ButtonStyle, Icon, IconSize};
use super::button_icon::ButtonIcon;
@@ -55,6 +55,13 @@ impl Selectable for IconButton {
}
}
+impl SelectableButton for IconButton {
+ fn selected_style(mut self, style: ButtonStyle) -> Self {
+ self.base = self.base.selected_style(style);
+ self
+ }
+}
+
impl Clickable for IconButton {
fn on_click(
mut self,
@@ -109,12 +116,14 @@ impl RenderOnce for IconButton {
fn render(self, _cx: &mut WindowContext) -> impl IntoElement {
let is_disabled = self.base.disabled;
let is_selected = self.base.selected;
+ let selected_style = self.base.selected_style;
self.base.child(
ButtonIcon::new(self.icon)
.disabled(is_disabled)
.selected(is_selected)
.selected_icon(self.selected_icon)
+ .when_some(selected_style, |this, style| this.selected_style(style))
.size(self.icon_size)
.color(self.icon_color),
)
@@ -63,6 +63,13 @@ impl Selectable for ToggleButton {
}
}
+impl SelectableButton for ToggleButton {
+ fn selected_style(mut self, style: ButtonStyle) -> Self {
+ self.base.selected_style = Some(style);
+ self
+ }
+}
+
impl Disableable for ToggleButton {
fn disabled(mut self, disabled: bool) -> Self {
self.base = self.base.disabled(disabled);
@@ -126,13 +126,14 @@ impl RenderOnce for Tab {
if self.selected {
this.border_l().border_r().pb_px()
} else {
- this.pr_px().pl_px().border_b()
+ this.pr_px().pl_px().border_b().border_r()
}
}
TabPosition::Middle(Ordering::Equal) => this.border_l().border_r().pb_px(),
TabPosition::Middle(Ordering::Less) => this.border_l().pr_px().border_b(),
TabPosition::Middle(Ordering::Greater) => this.border_r().pl_px().border_b(),
})
+ .cursor_pointer()
.child(
h_stack()
.group("")
@@ -12,7 +12,7 @@ pub use crate::selectable::*;
pub use crate::styles::{vh, vw};
pub use crate::visible_on_hover::*;
pub use crate::{h_stack, v_stack};
-pub use crate::{Button, ButtonSize, ButtonStyle, IconButton};
+pub use crate::{Button, ButtonSize, ButtonStyle, IconButton, SelectableButton};
pub use crate::{ButtonCommon, Color, StyledExt};
pub use crate::{Icon, IconElement, IconPosition, IconSize};
pub use crate::{Label, LabelCommon, LabelSize, LineHeightStyle};
@@ -59,153 +59,159 @@ pub struct WelcomePage {
impl Render for WelcomePage {
fn render(&mut self, cx: &mut gpui::ViewContext<Self>) -> impl IntoElement {
- h_stack().full().track_focus(&self.focus_handle).child(
- v_stack()
- .w_96()
- .gap_4()
- .mx_auto()
- .child(
- svg()
- .path("icons/logo_96.svg")
- .text_color(gpui::white())
- .w(px(96.))
- .h(px(96.))
- .mx_auto(),
- )
- .child(
- h_stack()
- .justify_center()
- .child(Label::new("Code at the speed of thought")),
- )
- .child(
- v_stack()
- .gap_2()
- .child(
- Button::new("choose-theme", "Choose a theme")
- .full_width()
- .on_click(cx.listener(|this, _, cx| {
- this.workspace
- .update(cx, |workspace, cx| {
- theme_selector::toggle(
- workspace,
- &Default::default(),
- cx,
- )
- })
- .ok();
- })),
- )
- .child(
- Button::new("choose-keymap", "Choose a keymap")
- .full_width()
- .on_click(cx.listener(|this, _, cx| {
- this.workspace
- .update(cx, |workspace, cx| {
- base_keymap_picker::toggle(
- workspace,
- &Default::default(),
- cx,
- )
- })
- .ok();
- })),
- )
- .child(
- Button::new("install-cli", "Install the CLI")
- .full_width()
- .on_click(cx.listener(|_, _, cx| {
- cx.app_mut()
- .spawn(
- |cx| async move { install_cli::install_cli(&cx).await },
+ h_stack()
+ .full()
+ .bg(cx.theme().colors().editor_background)
+ .track_focus(&self.focus_handle)
+ .child(
+ v_stack()
+ .w_96()
+ .gap_4()
+ .mx_auto()
+ .child(
+ svg()
+ .path("icons/logo_96.svg")
+ .text_color(gpui::white())
+ .w(px(96.))
+ .h(px(96.))
+ .mx_auto(),
+ )
+ .child(
+ h_stack()
+ .justify_center()
+ .child(Label::new("Code at the speed of thought")),
+ )
+ .child(
+ v_stack()
+ .gap_2()
+ .child(
+ Button::new("choose-theme", "Choose a theme")
+ .full_width()
+ .on_click(cx.listener(|this, _, cx| {
+ this.workspace
+ .update(cx, |workspace, cx| {
+ theme_selector::toggle(
+ workspace,
+ &Default::default(),
+ cx,
+ )
+ })
+ .ok();
+ })),
+ )
+ .child(
+ Button::new("choose-keymap", "Choose a keymap")
+ .full_width()
+ .on_click(cx.listener(|this, _, cx| {
+ this.workspace
+ .update(cx, |workspace, cx| {
+ base_keymap_picker::toggle(
+ workspace,
+ &Default::default(),
+ cx,
+ )
+ })
+ .ok();
+ })),
+ )
+ .child(
+ Button::new("install-cli", "Install the CLI")
+ .full_width()
+ .on_click(cx.listener(|_, _, cx| {
+ cx.app_mut()
+ .spawn(|cx| async move {
+ install_cli::install_cli(&cx).await
+ })
+ .detach_and_log_err(cx);
+ })),
+ ),
+ )
+ .child(
+ v_stack()
+ .p_3()
+ .gap_2()
+ .bg(cx.theme().colors().elevated_surface_background)
+ .border_1()
+ .border_color(cx.theme().colors().border)
+ .rounded_md()
+ .child(
+ h_stack()
+ .gap_2()
+ .child(
+ Checkbox::new(
+ "enable-vim",
+ if VimModeSetting::get_global(cx).0 {
+ ui::Selection::Selected
+ } else {
+ ui::Selection::Unselected
+ },
)
- .detach_and_log_err(cx);
- })),
- ),
- )
- .child(
- v_stack()
- .p_3()
- .gap_2()
- .bg(cx.theme().colors().elevated_surface_background)
- .border_1()
- .border_color(cx.theme().colors().border)
- .rounded_md()
- .child(
- h_stack()
- .gap_2()
- .child(
- Checkbox::new(
- "enable-vim",
- if VimModeSetting::get_global(cx).0 {
- ui::Selection::Selected
- } else {
- ui::Selection::Unselected
- },
+ .on_click(
+ cx.listener(move |this, selection, cx| {
+ this.update_settings::<VimModeSetting>(
+ selection,
+ cx,
+ |setting, value| *setting = Some(value),
+ );
+ }),
+ ),
)
- .on_click(cx.listener(
- move |this, selection, cx| {
- this.update_settings::<VimModeSetting>(
- selection,
- cx,
- |setting, value| *setting = Some(value),
- );
- },
- )),
- )
- .child(Label::new("Enable vim mode")),
- )
- .child(
- h_stack()
- .gap_2()
- .child(
- Checkbox::new(
- "enable-telemetry",
- if TelemetrySettings::get_global(cx).metrics {
- ui::Selection::Selected
- } else {
- ui::Selection::Unselected
- },
+ .child(Label::new("Enable vim mode")),
+ )
+ .child(
+ h_stack()
+ .gap_2()
+ .child(
+ Checkbox::new(
+ "enable-telemetry",
+ if TelemetrySettings::get_global(cx).metrics {
+ ui::Selection::Selected
+ } else {
+ ui::Selection::Unselected
+ },
+ )
+ .on_click(
+ cx.listener(move |this, selection, cx| {
+ this.update_settings::<TelemetrySettings>(
+ selection,
+ cx,
+ |settings, value| {
+ settings.metrics = Some(value)
+ },
+ );
+ }),
+ ),
)
- .on_click(cx.listener(
- move |this, selection, cx| {
- this.update_settings::<TelemetrySettings>(
- selection,
- cx,
- |settings, value| settings.metrics = Some(value),
- );
- },
- )),
- )
- .child(Label::new("Send anonymous usage data")),
- )
- .child(
- h_stack()
- .gap_2()
- .child(
- Checkbox::new(
- "enable-crash",
- if TelemetrySettings::get_global(cx).diagnostics {
- ui::Selection::Selected
- } else {
- ui::Selection::Unselected
- },
+ .child(Label::new("Send anonymous usage data")),
+ )
+ .child(
+ h_stack()
+ .gap_2()
+ .child(
+ Checkbox::new(
+ "enable-crash",
+ if TelemetrySettings::get_global(cx).diagnostics {
+ ui::Selection::Selected
+ } else {
+ ui::Selection::Unselected
+ },
+ )
+ .on_click(
+ cx.listener(move |this, selection, cx| {
+ this.update_settings::<TelemetrySettings>(
+ selection,
+ cx,
+ |settings, value| {
+ settings.diagnostics = Some(value)
+ },
+ );
+ }),
+ ),
)
- .on_click(cx.listener(
- move |this, selection, cx| {
- this.update_settings::<TelemetrySettings>(
- selection,
- cx,
- |settings, value| {
- settings.diagnostics = Some(value)
- },
- );
- },
- )),
- )
- .child(Label::new("Send crash reports")),
- ),
- ),
- )
+ .child(Label::new("Send crash reports")),
+ ),
+ ),
+ )
}
}
@@ -32,6 +32,7 @@ language = { path = "../language" }
node_runtime = { path = "../node_runtime" }
project = { path = "../project" }
settings = { path = "../settings" }
+sqlez = { path = "../sqlez" }
terminal = { path = "../terminal" }
theme = { path = "../theme" }
util = { path = "../util" }
@@ -651,9 +651,13 @@ impl Render for PanelButtons {
&& panel.position_is_valid(position, cx)
{
let panel = panel.clone();
- menu = menu.entry(position.to_label(), None, move |cx| {
- panel.set_position(position, cx);
- })
+ menu = menu.entry(
+ format!("Dock {}", position.to_label()),
+ None,
+ move |cx| {
+ panel.set_position(position, cx);
+ },
+ )
}
}
menu
@@ -246,7 +246,15 @@ impl Member {
.size_full()
.child(pane.clone())
.when_some(leader_border, |this, color| {
- this.border_2().border_color(color)
+ this.child(
+ div()
+ .absolute()
+ .size_full()
+ .left_0()
+ .top_0()
+ .border_2()
+ .border_color(color),
+ )
})
.when_some(leader_status_box, |this, status_box| {
this.child(
@@ -6,7 +6,12 @@ use std::path::Path;
use anyhow::{anyhow, bail, Context, Result};
use db::{define_connection, query, sqlez::connection::Connection, sqlez_macros::sql};
-use gpui::{Axis, WindowBounds};
+use gpui::{point, size, Axis, Bounds, WindowBounds};
+
+use sqlez::{
+ bindable::{Bind, Column, StaticColumnCount},
+ statement::Statement,
+};
use util::{unzip_option, ResultExt};
use uuid::Uuid;
@@ -20,6 +25,121 @@ use model::{
use self::model::DockStructure;
+#[derive(Copy, Clone, Debug, PartialEq)]
+pub(crate) struct SerializedAxis(pub(crate) gpui::Axis);
+impl sqlez::bindable::StaticColumnCount for SerializedAxis {}
+impl sqlez::bindable::Bind for SerializedAxis {
+ fn bind(
+ &self,
+ statement: &sqlez::statement::Statement,
+ start_index: i32,
+ ) -> anyhow::Result<i32> {
+ match self.0 {
+ gpui::Axis::Horizontal => "Horizontal",
+ gpui::Axis::Vertical => "Vertical",
+ }
+ .bind(statement, start_index)
+ }
+}
+
+impl sqlez::bindable::Column for SerializedAxis {
+ fn column(
+ statement: &mut sqlez::statement::Statement,
+ start_index: i32,
+ ) -> anyhow::Result<(Self, i32)> {
+ String::column(statement, start_index).and_then(|(axis_text, next_index)| {
+ Ok((
+ match axis_text.as_str() {
+ "Horizontal" => Self(Axis::Horizontal),
+ "Vertical" => Self(Axis::Vertical),
+ _ => anyhow::bail!("Stored serialized item kind is incorrect"),
+ },
+ next_index,
+ ))
+ })
+ }
+}
+
+#[derive(Clone, Debug, PartialEq)]
+pub(crate) struct SerializedWindowsBounds(pub(crate) WindowBounds);
+
+impl StaticColumnCount for SerializedWindowsBounds {
+ fn column_count() -> usize {
+ 5
+ }
+}
+
+impl Bind for SerializedWindowsBounds {
+ fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> {
+ let (region, next_index) = match self.0 {
+ WindowBounds::Fullscreen => {
+ let next_index = statement.bind(&"Fullscreen", start_index)?;
+ (None, next_index)
+ }
+ WindowBounds::Maximized => {
+ let next_index = statement.bind(&"Maximized", start_index)?;
+ (None, next_index)
+ }
+ WindowBounds::Fixed(region) => {
+ let next_index = statement.bind(&"Fixed", start_index)?;
+ (Some(region), next_index)
+ }
+ };
+
+ statement.bind(
+ ®ion.map(|region| {
+ (
+ SerializedGlobalPixels(region.origin.x),
+ SerializedGlobalPixels(region.origin.y),
+ SerializedGlobalPixels(region.size.width),
+ SerializedGlobalPixels(region.size.height),
+ )
+ }),
+ next_index,
+ )
+ }
+}
+
+impl Column for SerializedWindowsBounds {
+ fn column(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> {
+ let (window_state, next_index) = String::column(statement, start_index)?;
+ let bounds = match window_state.as_str() {
+ "Fullscreen" => SerializedWindowsBounds(WindowBounds::Fullscreen),
+ "Maximized" => SerializedWindowsBounds(WindowBounds::Maximized),
+ "Fixed" => {
+ let ((x, y, width, height), _) = Column::column(statement, next_index)?;
+ let x: f64 = x;
+ let y: f64 = y;
+ let width: f64 = width;
+ let height: f64 = height;
+ SerializedWindowsBounds(WindowBounds::Fixed(Bounds {
+ origin: point(x.into(), y.into()),
+ size: size(width.into(), height.into()),
+ }))
+ }
+ _ => bail!("Window State did not have a valid string"),
+ };
+
+ Ok((bounds, next_index + 4))
+ }
+}
+
+#[derive(Clone, Debug, PartialEq)]
+struct SerializedGlobalPixels(gpui::GlobalPixels);
+impl sqlez::bindable::StaticColumnCount for SerializedGlobalPixels {}
+
+impl sqlez::bindable::Bind for SerializedGlobalPixels {
+ fn bind(
+ &self,
+ statement: &sqlez::statement::Statement,
+ start_index: i32,
+ ) -> anyhow::Result<i32> {
+ let this: f64 = self.0.into();
+ let this: f32 = this as _;
+ this.bind(statement, start_index)
+ }
+}
+
define_connection! {
// Current schema shape using pseudo-rust syntax:
//
@@ -181,7 +301,7 @@ impl WorkspaceDb {
/// Returns a serialized workspace for the given worktree_roots. If the passed array
/// is empty, the most recent workspace is returned instead. If no workspace for the
/// passed roots is stored, returns none.
- pub fn workspace_for_roots<P: AsRef<Path>>(
+ pub(crate) fn workspace_for_roots<P: AsRef<Path>>(
&self,
worktree_roots: &[P],
) -> Option<SerializedWorkspace> {
@@ -192,7 +312,7 @@ impl WorkspaceDb {
let (workspace_id, workspace_location, bounds, display, docks): (
WorkspaceId,
WorkspaceLocation,
- Option<WindowBounds>,
+ Option<SerializedWindowsBounds>,
Option<Uuid>,
DockStructure,
) = self
@@ -230,7 +350,7 @@ impl WorkspaceDb {
.get_center_pane_group(workspace_id)
.context("Getting center group")
.log_err()?,
- bounds,
+ bounds: bounds.map(|bounds| bounds.0),
display,
docks,
})
@@ -238,7 +358,7 @@ impl WorkspaceDb {
/// Saves a workspace using the worktree roots. Will garbage collect any workspaces
/// that used this workspace previously
- pub async fn save_workspace(&self, workspace: SerializedWorkspace) {
+ pub(crate) async fn save_workspace(&self, workspace: SerializedWorkspace) {
self.write(move |conn| {
conn.with_savepoint("update_worktrees", || {
// Clear out panes and pane_groups
@@ -367,7 +487,7 @@ impl WorkspaceDb {
type GroupKey = (Option<GroupId>, WorkspaceId);
type GroupOrPane = (
Option<GroupId>,
- Option<Axis>,
+ Option<SerializedAxis>,
Option<PaneId>,
Option<bool>,
Option<String>,
@@ -536,7 +656,7 @@ impl WorkspaceDb {
}
query! {
- pub async fn set_window_bounds(workspace_id: WorkspaceId, bounds: WindowBounds, display: Uuid) -> Result<()> {
+ pub(crate) async fn set_window_bounds(workspace_id: WorkspaceId, bounds: SerializedWindowsBounds, display: Uuid) -> Result<()> {
UPDATE workspaces
SET window_state = ?2,
window_x = ?3,
@@ -683,7 +803,7 @@ mod tests {
fn group(axis: Axis, children: Vec<SerializedPaneGroup>) -> SerializedPaneGroup {
SerializedPaneGroup::Group {
- axis,
+ axis: SerializedAxis(axis),
flexes: None,
children,
}
@@ -1,3 +1,4 @@
+use super::SerializedAxis;
use crate::{item::ItemHandle, ItemDeserializers, Member, Pane, PaneAxis, Workspace, WorkspaceId};
use anyhow::{Context, Result};
use async_recursion::async_recursion;
@@ -5,7 +6,7 @@ use db::sqlez::{
bindable::{Bind, Column, StaticColumnCount},
statement::Statement,
};
-use gpui::{AsyncWindowContext, Axis, Model, Task, View, WeakView, WindowBounds};
+use gpui::{AsyncWindowContext, Model, Task, View, WeakView, WindowBounds};
use project::Project;
use std::{
path::{Path, PathBuf},
@@ -54,13 +55,13 @@ impl Column for WorkspaceLocation {
}
#[derive(Debug, PartialEq, Clone)]
-pub struct SerializedWorkspace {
- pub id: WorkspaceId,
- pub location: WorkspaceLocation,
- pub center_group: SerializedPaneGroup,
- pub bounds: Option<WindowBounds>,
- pub display: Option<Uuid>,
- pub docks: DockStructure,
+pub(crate) struct SerializedWorkspace {
+ pub(crate) id: WorkspaceId,
+ pub(crate) location: WorkspaceLocation,
+ pub(crate) center_group: SerializedPaneGroup,
+ pub(crate) bounds: Option<WindowBounds>,
+ pub(crate) display: Option<Uuid>,
+ pub(crate) docks: DockStructure,
}
#[derive(Debug, PartialEq, Clone, Default)]
@@ -126,9 +127,9 @@ impl Bind for DockData {
}
#[derive(Debug, PartialEq, Clone)]
-pub enum SerializedPaneGroup {
+pub(crate) enum SerializedPaneGroup {
Group {
- axis: Axis,
+ axis: SerializedAxis,
flexes: Option<Vec<f32>>,
children: Vec<SerializedPaneGroup>,
},
@@ -183,7 +184,7 @@ impl SerializedPaneGroup {
}
Some((
- Member::Axis(PaneAxis::load(axis, members, flexes)),
+ Member::Axis(PaneAxis::load(axis.0, members, flexes)),
current_active_pane,
items,
))
@@ -42,9 +42,9 @@ use node_runtime::NodeRuntime;
use notifications::{simple_message_notification::MessageNotification, NotificationHandle};
pub use pane::*;
pub use pane_group::*;
-use persistence::DB;
+use persistence::{model::SerializedWorkspace, SerializedWindowsBounds, DB};
pub use persistence::{
- model::{ItemId, SerializedWorkspace, WorkspaceLocation},
+ model::{ItemId, WorkspaceLocation},
WorkspaceDb, DB as WORKSPACE_DB,
};
use postage::stream::Stream;
@@ -70,8 +70,9 @@ use util::ResultExt;
use uuid::Uuid;
pub use workspace_settings::{AutosaveSetting, WorkspaceSettings};
-use crate::persistence::model::{
- DockData, DockStructure, SerializedItem, SerializedPane, SerializedPaneGroup,
+use crate::persistence::{
+ model::{DockData, DockStructure, SerializedItem, SerializedPane, SerializedPaneGroup},
+ SerializedAxis,
};
lazy_static! {
@@ -107,6 +108,7 @@ actions!(
NewCenterTerminal,
ToggleTerminalFocus,
NewSearch,
+ DeploySearch,
Feedback,
Restart,
Welcome,
@@ -624,7 +626,11 @@ impl Workspace {
if let Some(display_uuid) = display.uuid().log_err() {
cx.background_executor()
- .spawn(DB.set_window_bounds(workspace_id, bounds, display_uuid))
+ .spawn(DB.set_window_bounds(
+ workspace_id,
+ SerializedWindowsBounds(bounds),
+ display_uuid,
+ ))
.detach_and_log_err(cx);
}
}
@@ -1186,7 +1192,7 @@ impl Workspace {
mut save_intent: SaveIntent,
cx: &mut ViewContext<Self>,
) -> Task<Result<bool>> {
- if self.project.read(cx).is_read_only() {
+ if self.project.read(cx).is_disconnected() {
return Task::ready(Ok(true));
}
let dirty_items = self
@@ -2509,7 +2515,7 @@ impl Workspace {
}
fn update_window_edited(&mut self, cx: &mut ViewContext<Self>) {
- let is_edited = !self.project.read(cx).is_read_only()
+ let is_edited = !self.project.read(cx).is_disconnected()
&& self
.items(cx)
.any(|item| item.has_conflict(cx) || item.is_dirty(cx));
@@ -2988,7 +2994,7 @@ impl Workspace {
flexes,
bounding_boxes: _,
}) => SerializedPaneGroup::Group {
- axis: *axis,
+ axis: SerializedAxis(*axis),
children: members
.iter()
.map(|member| build_serialized_pane_group(member, cx))
@@ -3265,6 +3271,7 @@ impl Workspace {
let user_store = project.read(cx).user_store();
let workspace_store = cx.new_model(|cx| WorkspaceStore::new(client.clone(), cx));
+ cx.activate_window();
let app_state = Arc::new(AppState {
languages: project.read(cx).languages().clone(),
workspace_store,
@@ -3633,7 +3640,7 @@ impl Render for Workspace {
})),
)
.child(self.status_bar.clone())
- .children(if self.project.read(cx).is_read_only() {
+ .children(if self.project.read(cx).is_disconnected() {
Some(DisconnectedOverlay)
} else {
None
@@ -4763,8 +4770,7 @@ mod tests {
});
// Deactivating the window saves the file.
- cx.simulate_deactivation();
- cx.executor().run_until_parked();
+ cx.deactivate_window();
item.update(cx, |item, _| assert_eq!(item.save_count, 1));
// Autosave on focus change.
@@ -4784,14 +4790,13 @@ mod tests {
item.update(cx, |item, _| assert_eq!(item.save_count, 2));
// Deactivating the window still saves the file.
- cx.simulate_activation();
+ cx.update(|cx| cx.activate_window());
item.update(cx, |item, cx| {
cx.focus_self();
item.is_dirty = true;
});
- cx.simulate_deactivation();
+ cx.deactivate_window();
- cx.executor().run_until_parked();
item.update(cx, |item, _| assert_eq!(item.save_count, 3));
// Autosave after delay.
@@ -150,14 +150,6 @@ pub fn app_menus() -> Vec<Menu<'static>> {
MenuItem::action("View Dependency Licenses", crate::OpenLicenses),
MenuItem::action("Show Welcome", workspace::Welcome),
MenuItem::separator(),
- // todo!(): Needs `feedback` crate.
- // MenuItem::action("Give us feedback", feedback::feedback_editor::GiveFeedback),
- // MenuItem::action(
- // "Copy System Specs Into Clipboard",
- // feedback::CopySystemSpecsIntoClipboard,
- // ),
- // MenuItem::action("File Bug Report", feedback::FileBugReport),
- // MenuItem::action("Request Feature", feedback::RequestFeature),
MenuItem::separator(),
MenuItem::action(
"Documentation",
@@ -18,11 +18,11 @@ pub use only_instance::*;
pub use open_listener::*;
use anyhow::{anyhow, Context as _};
-use futures::{channel::mpsc, StreamExt};
+use futures::{channel::mpsc, select_biased, StreamExt};
use project_panel::ProjectPanel;
use quick_action_bar::QuickActionBar;
use search::project_search::ProjectSearchBar;
-use settings::{initial_local_settings_content, load_default_keymap, KeymapFile, Settings};
+use settings::{initial_local_settings_content, KeymapFile, Settings, SettingsStore};
use std::{borrow::Cow, ops::Deref, sync::Arc};
use terminal_view::terminal_panel::TerminalPanel;
use util::{
@@ -32,6 +32,7 @@ use util::{
ResultExt,
};
use uuid::Uuid;
+use welcome::BaseKeymap;
use workspace::Pane;
use workspace::{
create_and_open_local_file, notifications::simple_message_notification::MessageNotification,
@@ -399,8 +400,6 @@ pub fn initialize_workspace(app_state: Arc<AppState>, cx: &mut AppContext) {
});
workspace.focus_handle(cx).focus(cx);
- //todo!()
- // load_default_keymap(cx);
})
.detach();
}
@@ -558,38 +557,60 @@ pub fn handle_keymap_file_changes(
mut user_keymap_file_rx: mpsc::UnboundedReceiver<String>,
cx: &mut AppContext,
) {
+ BaseKeymap::register(cx);
+
+ let (base_keymap_tx, mut base_keymap_rx) = mpsc::unbounded();
+ let mut old_base_keymap = *BaseKeymap::get_global(cx);
+ cx.observe_global::<SettingsStore>(move |cx| {
+ let new_base_keymap = *BaseKeymap::get_global(cx);
+ if new_base_keymap != old_base_keymap {
+ old_base_keymap = new_base_keymap.clone();
+ base_keymap_tx.unbounded_send(()).unwrap();
+ }
+ })
+ .detach();
+
+ load_default_keymap(cx);
+
cx.spawn(move |cx| async move {
- // let mut settings_subscription = None;
- while let Some(user_keymap_content) = user_keymap_file_rx.next().await {
- if let Some(keymap_content) = KeymapFile::parse(&user_keymap_content).log_err() {
- cx.update(|cx| reload_keymaps(cx, &keymap_content)).ok();
-
- // todo!()
- // let mut old_base_keymap = cx.read(|cx| *settings::get::<BaseKeymap>(cx));
- // drop(settings_subscription);
- // settings_subscription = Some(cx.update(|cx| {
- // cx.observe_global::<SettingsStore, _>(move |cx| {
- // let new_base_keymap = *settings::get::<BaseKeymap>(cx);
- // if new_base_keymap != old_base_keymap {
- // old_base_keymap = new_base_keymap.clone();
- // reload_keymaps(cx, &keymap_content);
- // }
- // })
- // }));
+ let mut user_keymap = KeymapFile::default();
+ loop {
+ select_biased! {
+ _ = base_keymap_rx.next() => {}
+ user_keymap_content = user_keymap_file_rx.next() => {
+ if let Some(user_keymap_content) = user_keymap_content {
+ if let Some(keymap_content) = KeymapFile::parse(&user_keymap_content).log_err() {
+ user_keymap = keymap_content;
+ } else {
+ continue
+ }
+ }
+ }
}
+
+ cx.update(|cx| reload_keymaps(cx, &user_keymap)).ok();
}
})
.detach();
}
fn reload_keymaps(cx: &mut AppContext, keymap_content: &KeymapFile) {
- // todo!()
- // cx.clear_bindings();
+ cx.clear_key_bindings();
load_default_keymap(cx);
keymap_content.clone().add_to_cx(cx).log_err();
cx.set_menus(app_menus());
}
+pub fn load_default_keymap(cx: &mut AppContext) {
+ for path in ["keymaps/default.json", "keymaps/vim.json"] {
+ KeymapFile::load_asset(path, cx).unwrap();
+ }
+
+ if let Some(asset_path) = BaseKeymap::get_global(cx).asset_path() {
+ KeymapFile::load_asset(asset_path, cx).unwrap();
+ }
+}
+
fn open_local_settings_file(
workspace: &mut Workspace,
_: &OpenLocalSettings,
@@ -6,6 +6,11 @@ OUTPUT_FILE=$(pwd)/assets/licenses.md
> $OUTPUT_FILE
+echo -e "# ###### THEME LICENSES ######\n" >> $OUTPUT_FILE
+
+echo "Generating theme licenses"
+cat crates/theme/src/themes/LICENSES >> $OUTPUT_FILE
+
echo -e "# ###### CODE LICENSES ######\n" >> $OUTPUT_FILE
[[ "$(cargo about --version)" == "cargo-about 0.5.2" ]] || cargo install cargo-about --locked --git https://github.com/zed-industries/cargo-about --branch error-code-on-warn