From b9110c9268bd2af83fff1c55b4bc9a2da11844f3 Mon Sep 17 00:00:00 2001 From: Julia Date: Fri, 3 Mar 2023 13:10:08 -0800 Subject: [PATCH 01/93] Increase reconnect timeout Co-Authored-By: Antonio Scandurra --- crates/call/src/room.rs | 2 +- crates/collab/src/rpc.rs | 2 +- crates/rpc/src/peer.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/call/src/room.rs b/crates/call/src/room.rs index 06680c1dcb86335c2e120df3043fd413d3f26af1..901ae08fc048cf43c98131566855373d38686225 100644 --- a/crates/call/src/room.rs +++ b/crates/call/src/room.rs @@ -20,7 +20,7 @@ use project::Project; use std::{mem, sync::Arc, time::Duration}; use util::{post_inc, ResultExt, TryFutureExt}; -pub const RECONNECT_TIMEOUT: Duration = client::RECEIVE_TIMEOUT; +pub const RECONNECT_TIMEOUT: Duration = Duration::from_secs(30); #[derive(Clone, Debug, PartialEq, Eq)] pub enum Event { diff --git a/crates/collab/src/rpc.rs b/crates/collab/src/rpc.rs index 01d24024eb7516e87e4c0477d069cae8feb42da6..710ddcb890010342c4442e2154c7855e3f978afd 100644 --- a/crates/collab/src/rpc.rs +++ b/crates/collab/src/rpc.rs @@ -57,7 +57,7 @@ use tokio::sync::watch; use tower::ServiceBuilder; use tracing::{info_span, instrument, Instrument}; -pub const RECONNECT_TIMEOUT: Duration = Duration::from_secs(5); +pub const RECONNECT_TIMEOUT: Duration = Duration::from_secs(30); pub const CLEANUP_TIMEOUT: Duration = Duration::from_secs(10); lazy_static! { diff --git a/crates/rpc/src/peer.rs b/crates/rpc/src/peer.rs index 4740120fc4422c018042aa7564625a0ab900e760..0df87fd92d9ab92237ccefe98afe9b457cec9a49 100644 --- a/crates/rpc/src/peer.rs +++ b/crates/rpc/src/peer.rs @@ -114,7 +114,7 @@ pub struct ConnectionState { const KEEPALIVE_INTERVAL: Duration = Duration::from_secs(1); const WRITE_TIMEOUT: Duration = Duration::from_secs(2); -pub const RECEIVE_TIMEOUT: Duration = Duration::from_secs(5); +pub const RECEIVE_TIMEOUT: Duration = Duration::from_secs(10); impl Peer { pub fn new(epoch: u32) -> Arc { From 9401ef223d97f57ce33252675ac169b353213767 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Tue, 21 Feb 2023 18:16:47 -0800 Subject: [PATCH 02/93] Add welcome crate and associated types --- Cargo.lock | 15 +++++++++++ Cargo.toml | 1 + crates/welcome/Cargo.toml | 21 +++++++++++++++ crates/welcome/src/welcome.rs | 51 +++++++++++++++++++++++++++++++++++ crates/zed/Cargo.toml | 1 + crates/zed/src/main.rs | 1 + 6 files changed, 90 insertions(+) create mode 100644 crates/welcome/Cargo.toml create mode 100644 crates/welcome/src/welcome.rs diff --git a/Cargo.lock b/Cargo.lock index 2e7997458ed00185d5d1b48f2943eb0e657a1b41..607f47b5cf18944ca0c21de72c1047e6c328acde 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8013,6 +8013,20 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9193164d4de03a926d909d3bc7c30543cecb35400c02114792c2cae20d5e2dbb" +[[package]] +name = "welcome" +version = "0.1.0" +dependencies = [ + "anyhow", + "gpui", + "log", + "project", + "settings", + "theme", + "util", + "workspace", +] + [[package]] name = "wepoll-ffi" version = "0.1.2" @@ -8459,6 +8473,7 @@ dependencies = [ "util", "uuid 1.2.2", "vim", + "welcome", "workspace", ] diff --git a/Cargo.toml b/Cargo.toml index c74a76cccefe6c6de610b30c264a81e74b2654df..feb80633c4f48b63562f5adda2a22cd0062e94c8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -58,6 +58,7 @@ members = [ "crates/util", "crates/vim", "crates/workspace", + "crates/welcome", "crates/zed", ] default-members = ["crates/zed"] diff --git a/crates/welcome/Cargo.toml b/crates/welcome/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..6ac312c37ffbcdf21c9ec5583dc306b3da29ecc2 --- /dev/null +++ b/crates/welcome/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "welcome" +version = "0.1.0" +edition = "2021" +publish = false + +[lib] +path = "src/welcome.rs" + +[features] +test-support = [] + +[dependencies] +anyhow = "1.0.38" +log = "0.4" +gpui = { path = "../gpui" } +project = { path = "../project" } +settings = { path = "../settings" } +theme = { path = "../theme" } +util = { path = "../util" } +workspace = { path = "../workspace" } \ No newline at end of file diff --git a/crates/welcome/src/welcome.rs b/crates/welcome/src/welcome.rs new file mode 100644 index 0000000000000000000000000000000000000000..1deede76119bab32e193551b2c12f22455765085 --- /dev/null +++ b/crates/welcome/src/welcome.rs @@ -0,0 +1,51 @@ +use gpui::{ + actions, + elements::{Flex, Label, ParentElement}, + Element, Entity, MutableAppContext, View, +}; +use settings::Settings; +use workspace::{item::Item, Workspace}; + +actions!(welcome, [ShowWelcome]); + +pub fn init(cx: &mut MutableAppContext) { + cx.add_action(|workspace: &mut Workspace, _: &ShowWelcome, cx| { + let welcome_page = cx.add_view(|_cx| WelcomePage); + workspace.add_item(Box::new(welcome_page), cx) + }) +} + +struct WelcomePage; + +impl Entity for WelcomePage { + type Event = (); +} + +impl View for WelcomePage { + fn ui_name() -> &'static str { + "WelcomePage" + } + + fn render(&mut self, cx: &mut gpui::RenderContext<'_, Self>) -> gpui::ElementBox { + let theme = &cx.global::().theme; + Label::new("Welcome page", theme.editor.hover_popover.prose.clone()).boxed() + } +} + +impl Item for WelcomePage { + fn tab_content( + &self, + _detail: Option, + style: &theme::Tab, + _cx: &gpui::AppContext, + ) -> gpui::ElementBox { + Flex::row() + .with_child( + Label::new("Welcome to Zed!", style.label.clone()) + .aligned() + .contained() + .boxed(), + ) + .boxed() + } +} diff --git a/crates/zed/Cargo.toml b/crates/zed/Cargo.toml index 19c9a3d727704176f7d36b216719a3584d8c4a8d..d3b6e4810fa497cc41394d796a718e863af6f4dc 100644 --- a/crates/zed/Cargo.toml +++ b/crates/zed/Cargo.toml @@ -58,6 +58,7 @@ theme_testbench = { path = "../theme_testbench" } util = { path = "../util" } vim = { path = "../vim" } workspace = { path = "../workspace" } +welcome = { path = "../welcome" } anyhow = "1.0.38" async-compression = { version = "0.3", features = ["gzip", "futures-bufread"] } async-tar = "0.4.2" diff --git a/crates/zed/src/main.rs b/crates/zed/src/main.rs index b9e3ed550beb434c7da92138308131f09f3c8ac2..cc930774d58bb2a7d5f8dbc5912955eb6f3c736a 100644 --- a/crates/zed/src/main.rs +++ b/crates/zed/src/main.rs @@ -189,6 +189,7 @@ fn main() { zed::init(&app_state, cx); collab_ui::init(app_state.clone(), cx); feedback::init(app_state.clone(), cx); + welcome::init(cx); cx.set_menus(menus::menus()); From a0637a769ca0fde5af883c4004a7e164fd71e8ee Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Wed, 22 Feb 2023 12:01:59 -0800 Subject: [PATCH 03/93] WIP --- crates/welcome/src/welcome.rs | 34 ++++++++++++++++++++++++------- crates/workspace/src/workspace.rs | 7 ++++--- crates/zed/src/main.rs | 4 ++-- 3 files changed, 33 insertions(+), 12 deletions(-) diff --git a/crates/welcome/src/welcome.rs b/crates/welcome/src/welcome.rs index 1deede76119bab32e193551b2c12f22455765085..face85c4b6eb49fe6af491eba607f7b8e304a393 100644 --- a/crates/welcome/src/welcome.rs +++ b/crates/welcome/src/welcome.rs @@ -1,15 +1,13 @@ use gpui::{ - actions, - elements::{Flex, Label, ParentElement}, + color::Color, + elements::{Flex, Label, ParentElement, Svg}, Element, Entity, MutableAppContext, View, }; use settings::Settings; -use workspace::{item::Item, Workspace}; - -actions!(welcome, [ShowWelcome]); +use workspace::{item::Item, Welcome, Workspace}; pub fn init(cx: &mut MutableAppContext) { - cx.add_action(|workspace: &mut Workspace, _: &ShowWelcome, cx| { + cx.add_action(|workspace: &mut Workspace, _: &Welcome, cx| { let welcome_page = cx.add_view(|_cx| WelcomePage); workspace.add_item(Box::new(welcome_page), cx) }) @@ -28,7 +26,29 @@ impl View for WelcomePage { fn render(&mut self, cx: &mut gpui::RenderContext<'_, Self>) -> gpui::ElementBox { let theme = &cx.global::().theme; - Label::new("Welcome page", theme.editor.hover_popover.prose.clone()).boxed() + + Flex::new(gpui::Axis::Vertical) + .with_children([ + Flex::new(gpui::Axis::Horizontal) + .with_children([ + Svg::new("icons/terminal_16.svg") + .with_color(Color::red()) + .constrained() + .with_width(100.) + .with_height(100.) + .aligned() + .contained() + .boxed(), + Label::new("Zed", theme.editor.hover_popover.prose.clone()).boxed(), + ]) + .boxed(), + Label::new( + "Code at the speed of thought", + theme.editor.hover_popover.prose.clone(), + ) + .boxed(), + ]) + .boxed() } } diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index b9d80e7150fae064c2b34e80dee0507b7da22a2e..31960fbc1ec7751a147ecfcf788e26dd33ab1a0d 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -118,7 +118,8 @@ actions!( NewTerminal, NewSearch, Feedback, - Restart + Restart, + Welcome ] ); @@ -198,7 +199,7 @@ pub fn init(app_state: Arc, cx: &mut MutableAppContext) { }); cx.add_global_action({ let app_state = Arc::downgrade(&app_state); - move |_: &NewFile, cx: &mut MutableAppContext| { + move |_: &Welcome, cx: &mut MutableAppContext| { if let Some(app_state) = app_state.upgrade() { open_new(&app_state, cx).detach(); } @@ -2865,7 +2866,7 @@ pub fn open_new(app_state: &Arc, cx: &mut MutableAppContext) -> Task<( workspace.update(&mut cx, |_, cx| { if opened_paths.is_empty() { - cx.dispatch_action(NewFile); + cx.dispatch_action(Welcome); } }) }) diff --git a/crates/zed/src/main.rs b/crates/zed/src/main.rs index cc930774d58bb2a7d5f8dbc5912955eb6f3c736a..298e8ef8b9c50aff25f1b8bbf24c1b4f2559e37c 100644 --- a/crates/zed/src/main.rs +++ b/crates/zed/src/main.rs @@ -43,7 +43,7 @@ use theme::ThemeRegistry; use util::StaffMode; use util::{channel::RELEASE_CHANNEL, paths, ResultExt, TryFutureExt}; use workspace::{ - self, item::ItemHandle, notifications::NotifyResultExt, AppState, NewFile, OpenPaths, Workspace, + self, item::ItemHandle, notifications::NotifyResultExt, AppState, OpenPaths, Welcome, Workspace, }; use zed::{self, build_window_options, initialize_workspace, languages, menus}; @@ -260,7 +260,7 @@ async fn restore_or_create_workspace(mut cx: AsyncAppContext) { }); } else { cx.update(|cx| { - cx.dispatch_global_action(NewFile); + cx.dispatch_global_action(Welcome); }); } } From 416c79307695dc164ef2262a64f49c784a49fcc1 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Fri, 24 Feb 2023 14:31:59 -0800 Subject: [PATCH 04/93] Start on welcome experience settings --- Cargo.lock | 1 + crates/gpui/src/app.rs | 2 +- crates/settings/src/settings.rs | 180 ++++++++++++++++++++++++--- crates/settings/src/settings_file.rs | 50 ++------ crates/theme/src/theme.rs | 15 +++ crates/welcome/Cargo.toml | 1 + crates/welcome/src/welcome.rs | 107 ++++++++++++++-- styles/src/styleTree/app.ts | 2 + styles/src/styleTree/welcome.ts | 34 +++++ 9 files changed, 326 insertions(+), 66 deletions(-) create mode 100644 styles/src/styleTree/welcome.ts diff --git a/Cargo.lock b/Cargo.lock index 607f47b5cf18944ca0c21de72c1047e6c328acde..90da178c7bcb1afa8758f94bb7468983cb28d8d6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8018,6 +8018,7 @@ name = "welcome" version = "0.1.0" dependencies = [ "anyhow", + "editor", "gpui", "log", "project", diff --git a/crates/gpui/src/app.rs b/crates/gpui/src/app.rs index 31563010b723d88b4f834084fba91cb3ecd9a15c..0397032de89964e6a095039d315b614be2906102 100644 --- a/crates/gpui/src/app.rs +++ b/crates/gpui/src/app.rs @@ -5086,7 +5086,7 @@ impl From> for AnyWeakModelHandle { } } -#[derive(Debug)] +#[derive(Debug, Copy)] pub struct WeakViewHandle { window_id: usize, view_id: usize, diff --git a/crates/settings/src/settings.rs b/crates/settings/src/settings.rs index 6b51b06c9c0e4e3e8617c3bd26a58c7e902ed188..229e11ff3a22345b1be118ced67edbed8c3f3c7c 100644 --- a/crates/settings/src/settings.rs +++ b/crates/settings/src/settings.rs @@ -66,9 +66,18 @@ impl TelemetrySettings { pub fn metrics(&self) -> bool { self.metrics.unwrap() } + pub fn diagnostics(&self) -> bool { self.diagnostics.unwrap() } + + pub fn set_metrics(&mut self, value: bool) { + self.metrics = Some(value); + } + + pub fn set_diagnostics(&mut self, value: bool) { + self.diagnostics = Some(value); + } } #[derive(Copy, Clone, Debug, Default, Serialize, Deserialize, JsonSchema)] @@ -679,7 +688,7 @@ pub fn settings_file_json_schema( /// Expects the key to be unquoted, and the value to be valid JSON /// (e.g. values should be unquoted for numbers and bools, quoted for strings) -pub fn write_top_level_setting( +pub fn write_settings_key( mut settings_content: String, top_level_key: &str, new_val: &str, @@ -786,11 +795,160 @@ pub fn parse_json_with_comments(content: &str) -> Result )?) } +pub fn update_settings_file( + old_text: String, + old_file_content: SettingsFileContent, + update: impl FnOnce(&mut SettingsFileContent), +) -> String { + let mut new_file_content = old_file_content.clone(); + update(&mut new_file_content); + + let old_json = to_json_object(old_file_content); + let new_json = to_json_object(new_file_content); + + // Find changed fields + let mut diffs = vec![]; + for (key, old_value) in old_json.iter() { + let new_value = new_json.get(key).unwrap(); + if old_value != new_value { + if matches!( + new_value, + &Value::Null | &Value::Object(_) | &Value::Array(_) + ) { + unimplemented!("We only support updating basic values at the top level"); + } + + let new_json = serde_json::to_string_pretty(new_value) + .expect("Could not serialize new json field to string"); + + diffs.push((key, new_json)); + } + } + + let mut new_text = old_text; + for (key, new_value) in diffs { + new_text = write_settings_key(new_text, key, &new_value) + } + new_text +} + +fn to_json_object(settings_file: SettingsFileContent) -> serde_json::Map { + let tmp = serde_json::to_value(settings_file).unwrap(); + match tmp { + Value::Object(map) => map, + _ => unreachable!("SettingsFileContent represents a JSON map"), + } +} + #[cfg(test)] mod tests { - use crate::write_top_level_setting; + use super::*; use unindent::Unindent; + fn assert_new_settings, S2: Into>( + old_json: S1, + update: fn(&mut SettingsFileContent), + expected_new_json: S2, + ) { + let old_json = old_json.into(); + let old_content: SettingsFileContent = serde_json::from_str(&old_json).unwrap(); + let new_json = update_settings_file(old_json, old_content, update); + assert_eq!(new_json, expected_new_json.into()); + } + + #[test] + fn test_update_telemetry_setting_multiple_fields() { + assert_new_settings( + r#"{ + "telemetry": { + "metrics": false, + "diagnostics": false + } + }"# + .unindent(), + |settings| { + settings.telemetry.set_diagnostics(true); + settings.telemetry.set_metrics(true); + }, + r#"{ + "telemetry": { + "metrics": true, + "diagnostics": true + } + }"# + .unindent(), + ); + } + + #[test] + fn test_update_telemetry_setting_weird_formatting() { + assert_new_settings( + r#"{ + "telemetry": { "metrics": false, "diagnostics": true } + }"# + .unindent(), + |settings| settings.telemetry.set_diagnostics(false), + r#"{ + "telemetry": { "metrics": false, "diagnostics": false } + }"# + .unindent(), + ); + } + + #[test] + fn test_update_telemetry_setting_other_fields() { + assert_new_settings( + r#"{ + "telemetry": { + "metrics": false, + "diagnostics": true + } + }"# + .unindent(), + |settings| settings.telemetry.set_diagnostics(false), + r#"{ + "telemetry": { + "metrics": false, + "diagnostics": false + } + }"# + .unindent(), + ); + } + + #[test] + fn test_update_telemetry_setting_pre_existing() { + assert_new_settings( + r#"{ + "telemetry": { + "diagnostics": true + } + }"# + .unindent(), + |settings| settings.telemetry.set_diagnostics(false), + r#"{ + "telemetry": { + "diagnostics": false + } + }"# + .unindent(), + ); + } + + #[test] + fn test_update_telemetry_setting() { + assert_new_settings( + "{}", + |settings| settings.telemetry.set_diagnostics(true), + r#"{ + "telemetry": { + "diagnostics": true + } + }"# + .unindent(), + ); + } + #[test] fn test_write_theme_into_settings_with_theme() { let settings = r#" @@ -807,8 +965,7 @@ mod tests { "# .unindent(); - let settings_after_theme = - write_top_level_setting(settings, "theme", "\"summerfruit-light\""); + let settings_after_theme = write_settings_key(settings, "theme", "\"summerfruit-light\""); assert_eq!(settings_after_theme, new_settings) } @@ -828,8 +985,7 @@ mod tests { "# .unindent(); - let settings_after_theme = - write_top_level_setting(settings, "theme", "\"summerfruit-light\""); + let settings_after_theme = write_settings_key(settings, "theme", "\"summerfruit-light\""); assert_eq!(settings_after_theme, new_settings) } @@ -845,8 +1001,7 @@ mod tests { "# .unindent(); - let settings_after_theme = - write_top_level_setting(settings, "theme", "\"summerfruit-light\""); + let settings_after_theme = write_settings_key(settings, "theme", "\"summerfruit-light\""); assert_eq!(settings_after_theme, new_settings) } @@ -856,8 +1011,7 @@ mod tests { let settings = r#"{ "a": "", "ok": true }"#.to_string(); let new_settings = r#"{ "theme": "summerfruit-light", "a": "", "ok": true }"#; - let settings_after_theme = - write_top_level_setting(settings, "theme", "\"summerfruit-light\""); + let settings_after_theme = write_settings_key(settings, "theme", "\"summerfruit-light\""); assert_eq!(settings_after_theme, new_settings) } @@ -867,8 +1021,7 @@ mod tests { let settings = r#" { "a": "", "ok": true }"#.to_string(); let new_settings = r#" { "theme": "summerfruit-light", "a": "", "ok": true }"#; - let settings_after_theme = - write_top_level_setting(settings, "theme", "\"summerfruit-light\""); + let settings_after_theme = write_settings_key(settings, "theme", "\"summerfruit-light\""); assert_eq!(settings_after_theme, new_settings) } @@ -890,8 +1043,7 @@ mod tests { "# .unindent(); - let settings_after_theme = - write_top_level_setting(settings, "theme", "\"summerfruit-light\""); + let settings_after_theme = write_settings_key(settings, "theme", "\"summerfruit-light\""); assert_eq!(settings_after_theme, new_settings) } diff --git a/crates/settings/src/settings_file.rs b/crates/settings/src/settings_file.rs index 506ebc8c3ddea5eafa35259b77b7e000be737584..575e9499d38a26008bea65a86907bbd31306db1c 100644 --- a/crates/settings/src/settings_file.rs +++ b/crates/settings/src/settings_file.rs @@ -1,8 +1,7 @@ -use crate::{watched_json::WatchedJsonFile, write_top_level_setting, SettingsFileContent}; +use crate::{update_settings_file, watched_json::WatchedJsonFile, SettingsFileContent}; use anyhow::Result; use fs::Fs; use gpui::MutableAppContext; -use serde_json::Value; use std::{path::Path, sync::Arc}; // TODO: Switch SettingsFile to open a worktree and buffer for synchronization @@ -27,57 +26,24 @@ impl SettingsFile { } } - pub fn update(cx: &mut MutableAppContext, update: impl FnOnce(&mut SettingsFileContent)) { + pub fn update( + cx: &mut MutableAppContext, + update: impl 'static + Send + FnOnce(&mut SettingsFileContent), + ) { let this = cx.global::(); let current_file_content = this.settings_file_content.current(); - let mut new_file_content = current_file_content.clone(); - - update(&mut new_file_content); let fs = this.fs.clone(); let path = this.path.clone(); cx.background() .spawn(async move { - // Unwrap safety: These values are all guarnteed to be well formed, and we know - // that they will deserialize to our settings object. All of the following unwraps - // are therefore safe. - let tmp = serde_json::to_value(current_file_content).unwrap(); - let old_json = tmp.as_object().unwrap(); - - let new_tmp = serde_json::to_value(new_file_content).unwrap(); - let new_json = new_tmp.as_object().unwrap(); - - // Find changed fields - let mut diffs = vec![]; - for (key, old_value) in old_json.iter() { - let new_value = new_json.get(key).unwrap(); - if old_value != new_value { - if matches!( - new_value, - &Value::Null | &Value::Object(_) | &Value::Array(_) - ) { - unimplemented!( - "We only support updating basic values at the top level" - ); - } - - let new_json = serde_json::to_string_pretty(new_value) - .expect("Could not serialize new json field to string"); - - diffs.push((key, new_json)); - } - } + let old_text = fs.load(path).await?; - // Have diffs, rewrite the settings file now. - let mut content = fs.load(path).await?; - - for (key, new_value) in diffs { - content = write_top_level_setting(content, key, &new_value) - } + let new_text = update_settings_file(old_text, current_file_content, update); - fs.atomic_write(path.to_path_buf(), content).await?; + fs.atomic_write(path.to_path_buf(), new_text).await?; Ok(()) as Result<()> }) diff --git a/crates/theme/src/theme.rs b/crates/theme/src/theme.rs index 484c542edeffce8b22c8f2f29ae4f672c0693399..49f2d982ba475a60c94fa6f3e0e045db3b758cb8 100644 --- a/crates/theme/src/theme.rs +++ b/crates/theme/src/theme.rs @@ -37,6 +37,7 @@ pub struct Theme { pub tooltip: TooltipStyle, pub terminal: TerminalStyle, pub feedback: FeedbackStyle, + pub welcome: WelcomeStyle, pub color_scheme: ColorScheme, } @@ -850,6 +851,20 @@ pub struct FeedbackStyle { pub link_text_hover: ContainedText, } +#[derive(Clone, Deserialize, Default)] +pub struct WelcomeStyle { + pub checkbox: CheckboxStyle, +} + +#[derive(Clone, Deserialize, Default)] +pub struct CheckboxStyle { + pub width: f32, + pub height: f32, + pub unchecked: ContainerStyle, + pub checked: ContainerStyle, + pub hovered: ContainerStyle, +} + #[derive(Clone, Deserialize, Default)] pub struct ColorScheme { pub name: String, diff --git a/crates/welcome/Cargo.toml b/crates/welcome/Cargo.toml index 6ac312c37ffbcdf21c9ec5583dc306b3da29ecc2..3e450e2312794188f3ba9e3401fe80affeab6ad9 100644 --- a/crates/welcome/Cargo.toml +++ b/crates/welcome/Cargo.toml @@ -13,6 +13,7 @@ test-support = [] [dependencies] anyhow = "1.0.38" log = "0.4" +editor = { path = "../editor" } gpui = { path = "../gpui" } project = { path = "../project" } settings = { path = "../settings" } diff --git a/crates/welcome/src/welcome.rs b/crates/welcome/src/welcome.rs index face85c4b6eb49fe6af491eba607f7b8e304a393..385a8a5f00372dab695a20392b8438ce7694508d 100644 --- a/crates/welcome/src/welcome.rs +++ b/crates/welcome/src/welcome.rs @@ -1,19 +1,22 @@ use gpui::{ color::Color, - elements::{Flex, Label, ParentElement, Svg}, - Element, Entity, MutableAppContext, View, + elements::{Empty, Flex, Label, MouseEventHandler, ParentElement, Svg}, + Element, ElementBox, Entity, MutableAppContext, RenderContext, Subscription, View, ViewContext, }; -use settings::Settings; +use settings::{settings_file::SettingsFile, Settings, SettingsFileContent}; +use theme::CheckboxStyle; use workspace::{item::Item, Welcome, Workspace}; pub fn init(cx: &mut MutableAppContext) { cx.add_action(|workspace: &mut Workspace, _: &Welcome, cx| { - let welcome_page = cx.add_view(|_cx| WelcomePage); + let welcome_page = cx.add_view(WelcomePage::new); workspace.add_item(Box::new(welcome_page), cx) }) } -struct WelcomePage; +struct WelcomePage { + _settings_subscription: Subscription, +} impl Entity for WelcomePage { type Event = (); @@ -24,12 +27,21 @@ impl View for WelcomePage { "WelcomePage" } - fn render(&mut self, cx: &mut gpui::RenderContext<'_, Self>) -> gpui::ElementBox { - let theme = &cx.global::().theme; + fn render(&mut self, cx: &mut gpui::RenderContext<'_, Self>) -> ElementBox { + let settings = cx.global::(); + let theme = settings.theme.clone(); + + let (diagnostics, metrics) = { + let telemetry = settings.telemetry(); + (telemetry.diagnostics(), telemetry.metrics()) + }; + + enum Metrics {} + enum Diagnostics {} - Flex::new(gpui::Axis::Vertical) + Flex::column() .with_children([ - Flex::new(gpui::Axis::Horizontal) + Flex::row() .with_children([ Svg::new("icons/terminal_16.svg") .with_color(Color::red()) @@ -47,11 +59,88 @@ impl View for WelcomePage { theme.editor.hover_popover.prose.clone(), ) .boxed(), + Flex::row() + .with_children([ + self.render_settings_checkbox::( + &theme.welcome.checkbox, + metrics, + cx, + |content, checked| { + content.telemetry.set_metrics(checked); + }, + ), + Label::new( + "Do you want to send telemetry?", + theme.editor.hover_popover.prose.clone(), + ) + .boxed(), + ]) + .boxed(), + Flex::row() + .with_children([ + self.render_settings_checkbox::( + &theme.welcome.checkbox, + diagnostics, + cx, + |content, checked| content.telemetry.set_diagnostics(checked), + ), + Label::new( + "Send crash reports", + theme.editor.hover_popover.prose.clone(), + ) + .boxed(), + ]) + .boxed(), ]) + .aligned() .boxed() } } +impl WelcomePage { + fn new(cx: &mut ViewContext) -> Self { + let handle = cx.weak_handle(); + + let settings_subscription = cx.observe_global::(move |cx| { + if let Some(handle) = handle.upgrade(cx) { + handle.update(cx, |_, cx| cx.notify()) + } + }); + + WelcomePage { + _settings_subscription: settings_subscription, + } + } + + fn render_settings_checkbox( + &self, + style: &CheckboxStyle, + checked: bool, + cx: &mut RenderContext, + set_value: fn(&mut SettingsFileContent, checked: bool) -> (), + ) -> ElementBox { + MouseEventHandler::::new(0, cx, |state, _| { + Empty::new() + .constrained() + .with_width(style.width) + .with_height(style.height) + .contained() + .with_style(if checked { + style.checked + } else if state.hovered() { + style.hovered + } else { + style.unchecked + }) + .boxed() + }) + .on_click(gpui::MouseButton::Left, move |_, cx| { + SettingsFile::update(cx, move |content| set_value(content, !checked)) + }) + .boxed() + } +} + impl Item for WelcomePage { fn tab_content( &self, diff --git a/styles/src/styleTree/app.ts b/styles/src/styleTree/app.ts index dc57468df65f079af5eb5af7596823024b5d4df2..423ce37d481e8f47bf9118ad6134b5c123a4ed31 100644 --- a/styles/src/styleTree/app.ts +++ b/styles/src/styleTree/app.ts @@ -20,6 +20,7 @@ import contactList from "./contactList" import incomingCallNotification from "./incomingCallNotification" import { ColorScheme } from "../themes/common/colorScheme" import feedback from "./feedback" +import welcome from "./welcome" export default function app(colorScheme: ColorScheme): Object { return { @@ -33,6 +34,7 @@ export default function app(colorScheme: ColorScheme): Object { incomingCallNotification: incomingCallNotification(colorScheme), picker: picker(colorScheme), workspace: workspace(colorScheme), + welcome: welcome(colorScheme), contextMenu: contextMenu(colorScheme), editor: editor(colorScheme), projectDiagnostics: projectDiagnostics(colorScheme), diff --git a/styles/src/styleTree/welcome.ts b/styles/src/styleTree/welcome.ts new file mode 100644 index 0000000000000000000000000000000000000000..f1325514cdd0771b7f5d9b9570a9345d9e0f5b2e --- /dev/null +++ b/styles/src/styleTree/welcome.ts @@ -0,0 +1,34 @@ + +import { ColorScheme } from "../themes/common/colorScheme"; +import { border } from "./components"; + +export default function welcome(colorScheme: ColorScheme) { + let layer = colorScheme.highest; + + // TODO + let checkbox_base = { + background: colorScheme.ramps.red(0.5).hex(), + cornerRadius: 8, + padding: { + left: 8, + right: 8, + top: 4, + bottom: 4, + }, + shadow: colorScheme.popoverShadow, + border: border(layer), + margin: { + left: -8, + }, + }; + + return { + checkbox: { + width: 9, + height: 9, + unchecked: checkbox_base, + checked: checkbox_base, + hovered: checkbox_base + } + } +} \ No newline at end of file From 50586812ecdbca1f8fa538a708122dafd52bba9c Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Fri, 24 Feb 2023 14:41:16 -0800 Subject: [PATCH 05/93] Make generate licenses quieter --- script/generate-licenses | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/generate-licenses b/script/generate-licenses index 8a41f55c025bf4909b4298180588f043a6153894..14c9d4c79f1646d4889da82d9ee24c7975003532 100755 --- a/script/generate-licenses +++ b/script/generate-licenses @@ -10,7 +10,7 @@ echo -e "# ###### THEME LICENSES ######\n" >> $OUTPUT_FILE echo "Generating theme licenses" cd styles -npm ci +npm --silent ci npm run --silent build-licenses >> $OUTPUT_FILE cd .. From 86e21015922487c20cacba5f93ecf588142a89c8 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Fri, 24 Feb 2023 16:43:34 -0800 Subject: [PATCH 06/93] Added the ability to nested values to the settings file, while preserving user formatting co-authored-by: max --- crates/settings/src/settings.rs | 479 ++++++++++++++++++++------------ 1 file changed, 294 insertions(+), 185 deletions(-) diff --git a/crates/settings/src/settings.rs b/crates/settings/src/settings.rs index 229e11ff3a22345b1be118ced67edbed8c3f3c7c..501a88c42e14bcb3da9cadaa3f889a63580830df 100644 --- a/crates/settings/src/settings.rs +++ b/crates/settings/src/settings.rs @@ -18,7 +18,7 @@ use sqlez::{ bindable::{Bind, Column, StaticColumnCount}, statement::Statement, }; -use std::{collections::HashMap, fmt::Write as _, num::NonZeroU32, str, sync::Arc}; +use std::{collections::HashMap, num::NonZeroU32, str, sync::Arc}; use theme::{Theme, ThemeRegistry}; use tree_sitter::Query; use util::ResultExt as _; @@ -686,13 +686,25 @@ pub fn settings_file_json_schema( serde_json::to_value(root_schema).unwrap() } +fn merge(target: &mut T, value: Option) { + if let Some(value) = value { + *target = value; + } +} + +pub fn parse_json_with_comments(content: &str) -> Result { + Ok(serde_json::from_reader( + json_comments::CommentSettings::c_style().strip_comments(content.as_bytes()), + )?) +} + /// Expects the key to be unquoted, and the value to be valid JSON /// (e.g. values should be unquoted for numbers and bools, quoted for strings) -pub fn write_settings_key( - mut settings_content: String, - top_level_key: &str, - new_val: &str, -) -> String { +pub fn write_settings_key( + settings_content: &mut String, + key_path: &[&str], + new_value: &T, +) { let mut parser = tree_sitter::Parser::new(); parser.set_language(tree_sitter_json::language()).unwrap(); let tree = parser.parse(&settings_content, None).unwrap(); @@ -702,56 +714,64 @@ pub fn write_settings_key( let query = Query::new( tree_sitter_json::language(), " - (document - (object - (pair - key: (string) @key - value: (_) @value))) - ", + (pair + key: (string) @key + value: (_) @value) + ", ) .unwrap(); + let mut depth = 0; let mut first_key_start = None; - let mut existing_value_range = None; + let mut existing_value_range = 0..settings_content.len(); let matches = cursor.matches(&query, tree.root_node(), settings_content.as_bytes()); for mat in matches { if mat.captures.len() != 2 { continue; } - let key = mat.captures[0]; - let value = mat.captures[1]; + let key_range = mat.captures[0].node.byte_range(); + let value_range = mat.captures[1].node.byte_range(); + + if key_range.start > existing_value_range.end { + break; + } + + first_key_start.get_or_insert_with(|| key_range.start); + + let found_key = settings_content + .get(key_range.clone()) + .map(|key_text| key_text == format!("\"{}\"", key_path[depth])) + .unwrap_or(false); - first_key_start.get_or_insert_with(|| key.node.start_byte()); + if found_key { + existing_value_range = value_range; + depth += 1; - if let Some(key_text) = settings_content.get(key.node.byte_range()) { - if key_text == format!("\"{top_level_key}\"") { - existing_value_range = Some(value.node.byte_range()); + if depth == key_path.len() { break; + } else { + first_key_start = None; } } } - match (first_key_start, existing_value_range) { - (None, None) => { - // No document, create a new object and overwrite - settings_content.clear(); - write!( - settings_content, - "{{\n \"{}\": {new_val}\n}}\n", - top_level_key - ) - .unwrap(); - } - - (_, Some(existing_value_range)) => { - // Existing theme key, overwrite - settings_content.replace_range(existing_value_range, &new_val); + // We found the exact key we want, insert the new value + if depth == key_path.len() { + let new_val = serde_json::to_string_pretty(new_value) + .expect("Could not serialize new json field to string"); + settings_content.replace_range(existing_value_range, &new_val); + } else { + // We have key paths, construct the sub objects + let new_key = key_path[depth]; + + // We don't have the key, construct the nested objects + let mut new_value = serde_json::to_value(new_value).unwrap(); + for key in key_path[(depth + 1)..].iter().rev() { + new_value = serde_json::json!({ key.to_string(): new_value }); } - (Some(first_key_start), None) => { - // No existing theme key, but other settings. Prepend new theme settings and - // match style of first key + if let Some(first_key_start) = first_key_start { let mut row = 0; let mut column = 0; for (ix, char) in settings_content.char_indices() { @@ -766,70 +786,118 @@ pub fn write_settings_key( } } - let content = format!(r#""{top_level_key}": {new_val},"#); - settings_content.insert_str(first_key_start, &content); - if row > 0 { + let new_val = to_pretty_json(&new_value, column, column); + let content = format!(r#""{new_key}": {new_val},"#); + settings_content.insert_str(first_key_start, &content); + settings_content.insert_str( first_key_start + content.len(), &format!("\n{:width$}", ' ', width = column), ) } else { - settings_content.insert_str(first_key_start + content.len(), " ") + let new_val = serde_json::to_string(&new_value).unwrap(); + let mut content = format!(r#""{new_key}": {new_val},"#); + content.push(' '); + settings_content.insert_str(first_key_start, &content); + } + } else { + new_value = serde_json::json!({ new_key.to_string(): new_value }); + let indent_prefix_len = 4 * depth; + let new_val = to_pretty_json(&new_value, 4, indent_prefix_len); + + settings_content.replace_range(existing_value_range, &new_val); + if depth == 0 { + settings_content.push('\n'); } } } - - settings_content } -fn merge(target: &mut T, value: Option) { - if let Some(value) = value { - *target = value; - } -} +fn to_pretty_json( + value: &serde_json::Value, + indent_size: usize, + indent_prefix_len: usize, +) -> String { + const SPACES: [u8; 32] = [b' '; 32]; -pub fn parse_json_with_comments(content: &str) -> Result { - Ok(serde_json::from_reader( - json_comments::CommentSettings::c_style().strip_comments(content.as_bytes()), - )?) + debug_assert!(indent_size <= SPACES.len()); + debug_assert!(indent_prefix_len <= SPACES.len()); + + let mut output = Vec::new(); + let mut ser = serde_json::Serializer::with_formatter( + &mut output, + serde_json::ser::PrettyFormatter::with_indent(&SPACES[0..indent_size.min(SPACES.len())]), + ); + + value.serialize(&mut ser).unwrap(); + let text = String::from_utf8(output).unwrap(); + + let mut adjusted_text = String::new(); + for (i, line) in text.split('\n').enumerate() { + if i > 0 { + adjusted_text.push_str(str::from_utf8(&SPACES[0..indent_prefix_len]).unwrap()); + } + adjusted_text.push_str(line); + adjusted_text.push('\n'); + } + adjusted_text.pop(); + adjusted_text } pub fn update_settings_file( - old_text: String, + mut text: String, old_file_content: SettingsFileContent, update: impl FnOnce(&mut SettingsFileContent), ) -> String { let mut new_file_content = old_file_content.clone(); - update(&mut new_file_content); - let old_json = to_json_object(old_file_content); - let new_json = to_json_object(new_file_content); - - // Find changed fields - let mut diffs = vec![]; - for (key, old_value) in old_json.iter() { - let new_value = new_json.get(key).unwrap(); - if old_value != new_value { - if matches!( - new_value, - &Value::Null | &Value::Object(_) | &Value::Array(_) - ) { - unimplemented!("We only support updating basic values at the top level"); - } + update(&mut new_file_content); - let new_json = serde_json::to_string_pretty(new_value) - .expect("Could not serialize new json field to string"); + let old_object = to_json_object(old_file_content); + let new_object = to_json_object(new_file_content); - diffs.push((key, new_json)); + fn apply_changes_to_json_text( + old_object: &serde_json::Map, + new_object: &serde_json::Map, + current_key_path: Vec<&str>, + json_text: &mut String, + ) { + for (key, old_value) in old_object.iter() { + // We know that these two are from the same shape of object, so we can just unwrap + let new_value = new_object.get(key).unwrap(); + if old_value != new_value { + match new_value { + Value::Bool(_) | Value::Number(_) | Value::String(_) => { + let mut key_path = current_key_path.clone(); + key_path.push(key); + write_settings_key(json_text, &key_path, &new_value); + } + Value::Object(new_sub_object) => { + let mut key_path = current_key_path.clone(); + key_path.push(key); + if let Value::Object(old_sub_object) = old_value { + apply_changes_to_json_text( + old_sub_object, + new_sub_object, + key_path, + json_text, + ); + } else { + unimplemented!("This function doesn't support changing values from simple values to objects yet"); + } + } + Value::Null | Value::Array(_) => { + unimplemented!("We only support objects and simple values"); + } + } + } } } - let mut new_text = old_text; - for (key, new_value) in diffs { - new_text = write_settings_key(new_text, key, &new_value) - } - new_text + apply_changes_to_json_text(&old_object, &new_object, vec![], &mut text); + + text } fn to_json_object(settings_file: SettingsFileContent) -> serde_json::Map { @@ -851,7 +919,7 @@ mod tests { expected_new_json: S2, ) { let old_json = old_json.into(); - let old_content: SettingsFileContent = serde_json::from_str(&old_json).unwrap(); + let old_content: SettingsFileContent = serde_json::from_str(&old_json).unwrap_or_default(); let new_json = update_settings_file(old_json, old_content, update); assert_eq!(new_json, expected_new_json.into()); } @@ -859,23 +927,27 @@ mod tests { #[test] fn test_update_telemetry_setting_multiple_fields() { assert_new_settings( - r#"{ - "telemetry": { - "metrics": false, - "diagnostics": false + r#" + { + "telemetry": { + "metrics": false, + "diagnostics": false + } } - }"# + "# .unindent(), |settings| { settings.telemetry.set_diagnostics(true); settings.telemetry.set_metrics(true); }, - r#"{ - "telemetry": { - "metrics": true, - "diagnostics": true + r#" + { + "telemetry": { + "metrics": true, + "diagnostics": true + } } - }"# + "# .unindent(), ); } @@ -898,20 +970,45 @@ mod tests { #[test] fn test_update_telemetry_setting_other_fields() { assert_new_settings( - r#"{ - "telemetry": { - "metrics": false, - "diagnostics": true + r#" + { + "telemetry": { + "metrics": false, + "diagnostics": true + } } - }"# + "# .unindent(), |settings| settings.telemetry.set_diagnostics(false), - r#"{ - "telemetry": { - "metrics": false, - "diagnostics": false + r#" + { + "telemetry": { + "metrics": false, + "diagnostics": false + } } - }"# + "# + .unindent(), + ); + } + + #[test] + fn test_update_telemetry_setting_empty_telemetry() { + assert_new_settings( + r#" + { + "telemetry": {} + } + "# + .unindent(), + |settings| settings.telemetry.set_diagnostics(false), + r#" + { + "telemetry": { + "diagnostics": false + } + } + "# .unindent(), ); } @@ -919,18 +1016,22 @@ mod tests { #[test] fn test_update_telemetry_setting_pre_existing() { assert_new_settings( - r#"{ - "telemetry": { - "diagnostics": true + r#" + { + "telemetry": { + "diagnostics": true + } } - }"# + "# .unindent(), |settings| settings.telemetry.set_diagnostics(false), - r#"{ - "telemetry": { - "diagnostics": false + r#" + { + "telemetry": { + "diagnostics": false + } } - }"# + "# .unindent(), ); } @@ -940,111 +1041,119 @@ mod tests { assert_new_settings( "{}", |settings| settings.telemetry.set_diagnostics(true), - r#"{ - "telemetry": { - "diagnostics": true + r#" + { + "telemetry": { + "diagnostics": true + } } - }"# + "# .unindent(), ); } #[test] - fn test_write_theme_into_settings_with_theme() { - let settings = r#" - { - "theme": "One Dark" - } - "# - .unindent(); - - let new_settings = r#" - { - "theme": "summerfruit-light" - } - "# - .unindent(); - - let settings_after_theme = write_settings_key(settings, "theme", "\"summerfruit-light\""); + fn test_update_object_empty_doc() { + assert_new_settings( + "", + |settings| settings.telemetry.set_diagnostics(true), + r#" + { + "telemetry": { + "diagnostics": true + } + } + "# + .unindent(), + ); + } - assert_eq!(settings_after_theme, new_settings) + #[test] + fn test_write_theme_into_settings_with_theme() { + assert_new_settings( + r#" + { + "theme": "One Dark" + } + "# + .unindent(), + |settings| settings.theme = Some("summerfruit-light".to_string()), + r#" + { + "theme": "summerfruit-light" + } + "# + .unindent(), + ); } #[test] fn test_write_theme_into_empty_settings() { - let settings = r#" - { - } - "# - .unindent(); - - let new_settings = r#" - { - "theme": "summerfruit-light" - } - "# - .unindent(); - - let settings_after_theme = write_settings_key(settings, "theme", "\"summerfruit-light\""); - - assert_eq!(settings_after_theme, new_settings) + assert_new_settings( + r#" + { + } + "# + .unindent(), + |settings| settings.theme = Some("summerfruit-light".to_string()), + r#" + { + "theme": "summerfruit-light" + } + "# + .unindent(), + ); } #[test] - fn test_write_theme_into_no_settings() { - let settings = "".to_string(); - - let new_settings = r#" - { - "theme": "summerfruit-light" - } - "# - .unindent(); - - let settings_after_theme = write_settings_key(settings, "theme", "\"summerfruit-light\""); - - assert_eq!(settings_after_theme, new_settings) + fn write_key_no_document() { + assert_new_settings( + "", + |settings| settings.theme = Some("summerfruit-light".to_string()), + r#" + { + "theme": "summerfruit-light" + } + "# + .unindent(), + ); } #[test] fn test_write_theme_into_single_line_settings_without_theme() { - let settings = r#"{ "a": "", "ok": true }"#.to_string(); - let new_settings = r#"{ "theme": "summerfruit-light", "a": "", "ok": true }"#; - - let settings_after_theme = write_settings_key(settings, "theme", "\"summerfruit-light\""); - - assert_eq!(settings_after_theme, new_settings) + assert_new_settings( + r#"{ "a": "", "ok": true }"#, + |settings| settings.theme = Some("summerfruit-light".to_string()), + r#"{ "theme": "summerfruit-light", "a": "", "ok": true }"#, + ); } #[test] fn test_write_theme_pre_object_whitespace() { - let settings = r#" { "a": "", "ok": true }"#.to_string(); - let new_settings = r#" { "theme": "summerfruit-light", "a": "", "ok": true }"#; - - let settings_after_theme = write_settings_key(settings, "theme", "\"summerfruit-light\""); - - assert_eq!(settings_after_theme, new_settings) + assert_new_settings( + r#" { "a": "", "ok": true }"#, + |settings| settings.theme = Some("summerfruit-light".to_string()), + r#" { "theme": "summerfruit-light", "a": "", "ok": true }"#.unindent(), + ); } #[test] fn test_write_theme_into_multi_line_settings_without_theme() { - let settings = r#" - { - "a": "b" - } - "# - .unindent(); - - let new_settings = r#" - { - "theme": "summerfruit-light", - "a": "b" - } - "# - .unindent(); - - let settings_after_theme = write_settings_key(settings, "theme", "\"summerfruit-light\""); - - assert_eq!(settings_after_theme, new_settings) + assert_new_settings( + r#" + { + "a": "b" + } + "# + .unindent(), + |settings| settings.theme = Some("summerfruit-light".to_string()), + r#" + { + "theme": "summerfruit-light", + "a": "b" + } + "# + .unindent(), + ); } } From 118435a348e76ebcb43b3b0f8c6a04c5b3b66256 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Fri, 24 Feb 2023 17:04:31 -0800 Subject: [PATCH 07/93] Added basic styling for checkboxes, yay Co-authored-by: Max --- crates/theme/src/theme.rs | 3 ++- crates/welcome/src/welcome.rs | 14 ++++++++++---- styles/src/styleTree/welcome.ts | 33 +++++++++++++++++++++++++++------ 3 files changed, 39 insertions(+), 11 deletions(-) diff --git a/crates/theme/src/theme.rs b/crates/theme/src/theme.rs index 49f2d982ba475a60c94fa6f3e0e045db3b758cb8..87b9d9845a314d6db5a63c280b417c43a6dc43cf 100644 --- a/crates/theme/src/theme.rs +++ b/crates/theme/src/theme.rs @@ -860,9 +860,10 @@ pub struct WelcomeStyle { pub struct CheckboxStyle { pub width: f32, pub height: f32, - pub unchecked: ContainerStyle, + pub default: ContainerStyle, pub checked: ContainerStyle, pub hovered: ContainerStyle, + pub hovered_and_checked: ContainerStyle, } #[derive(Clone, Deserialize, Default)] diff --git a/crates/welcome/src/welcome.rs b/crates/welcome/src/welcome.rs index 385a8a5f00372dab695a20392b8438ce7694508d..6985b700690a0eac970ffa7082dd0fa7e8c867df 100644 --- a/crates/welcome/src/welcome.rs +++ b/crates/welcome/src/welcome.rs @@ -126,11 +126,17 @@ impl WelcomePage { .with_height(style.height) .contained() .with_style(if checked { - style.checked - } else if state.hovered() { - style.hovered + if state.hovered() { + style.hovered_and_checked + } else { + style.checked + } } else { - style.unchecked + if state.hovered() { + style.hovered + } else { + style.default + } }) .boxed() }) diff --git a/styles/src/styleTree/welcome.ts b/styles/src/styleTree/welcome.ts index f1325514cdd0771b7f5d9b9570a9345d9e0f5b2e..6085782afd009722784c5f70e6a835bb3fe0f1ef 100644 --- a/styles/src/styleTree/welcome.ts +++ b/styles/src/styleTree/welcome.ts @@ -6,9 +6,8 @@ export default function welcome(colorScheme: ColorScheme) { let layer = colorScheme.highest; // TODO - let checkbox_base = { - background: colorScheme.ramps.red(0.5).hex(), - cornerRadius: 8, + let checkboxBase = { + cornerRadius: 4, padding: { left: 8, right: 8, @@ -26,9 +25,31 @@ export default function welcome(colorScheme: ColorScheme) { checkbox: { width: 9, height: 9, - unchecked: checkbox_base, - checked: checkbox_base, - hovered: checkbox_base + default: { + ...checkboxBase, + background: colorScheme.ramps.blue(0.5).hex(), + }, + checked: { + ...checkboxBase, + background: colorScheme.ramps.red(0.5).hex(), + }, + hovered: { + ...checkboxBase, + background: colorScheme.ramps.blue(0.5).hex(), + + border: { + color: colorScheme.ramps.green(0.5).hex(), + width: 1, + } + }, + hoveredAndChecked: { + ...checkboxBase, + background: colorScheme.ramps.red(0.5).hex(), + border: { + color: colorScheme.ramps.green(0.5).hex(), + width: 1, + } + } } } } \ No newline at end of file From 7d7053b990419edc1772c8a370bb80976455dee0 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Tue, 28 Feb 2023 19:20:21 -0800 Subject: [PATCH 08/93] Move to using stateless --- Cargo.lock | 1 + assets/settings/default.json | 2 +- crates/db/src/db.rs | 3 ++- crates/zed/Cargo.toml | 1 + crates/zed/src/main.rs | 14 +++++++++++--- crates/zed/src/zed.rs | 25 ++++++++++++++++++++++++- 6 files changed, 40 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 90da178c7bcb1afa8758f94bb7468983cb28d8d6..c8124fcc3a180d2159a7bd8e5a690986f7dfa527 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8395,6 +8395,7 @@ dependencies = [ "command_palette", "context_menu", "ctor", + "db", "diagnostics", "easy-parallel", "editor", diff --git a/assets/settings/default.json b/assets/settings/default.json index 2a5e05b40138053862461f721231e042b2a1cb38..90c47478f3f7c3a97b50cea061907c122bf513c9 100644 --- a/assets/settings/default.json +++ b/assets/settings/default.json @@ -50,7 +50,7 @@ // "default_dock_anchor": "right" // 3. Position the dock full screen over the entire workspace" // "default_dock_anchor": "expanded" - "default_dock_anchor": "right", + "default_dock_anchor": "bottom", // Whether or not to remove any trailing whitespace from lines of a buffer // before saving it. "remove_trailing_whitespace_on_save": true, diff --git a/crates/db/src/db.rs b/crates/db/src/db.rs index 20f2300d89b591230dcc41df4008e8c1fc65ec7a..f4d0dc1a469a272b0f2422e4eb0e88e33def510e 100644 --- a/crates/db/src/db.rs +++ b/crates/db/src/db.rs @@ -39,7 +39,8 @@ const FALLBACK_DB_NAME: &'static str = "FALLBACK_MEMORY_DB"; const DB_FILE_NAME: &'static str = "db.sqlite"; lazy_static::lazy_static! { - static ref ZED_STATELESS: bool = std::env::var("ZED_STATELESS").map_or(false, |v| !v.is_empty()); + // !!!!!!! CHANGE BACK TO DEFAULT FALSE BEFORE SHIPPING + static ref ZED_STATELESS: bool = std::env::var("ZED_STATELESS").map_or(true, |v| !v.is_empty()); static ref DB_FILE_OPERATIONS: Mutex<()> = Mutex::new(()); pub static ref BACKUP_DB_PATH: RwLock> = RwLock::new(None); pub static ref ALL_FILE_DB_FAILED: AtomicBool = AtomicBool::new(false); diff --git a/crates/zed/Cargo.toml b/crates/zed/Cargo.toml index d3b6e4810fa497cc41394d796a718e863af6f4dc..68b04c7e2f846f549837f6aa7b77d1857d2243c3 100644 --- a/crates/zed/Cargo.toml +++ b/crates/zed/Cargo.toml @@ -29,6 +29,7 @@ context_menu = { path = "../context_menu" } client = { path = "../client" } clock = { path = "../clock" } diagnostics = { path = "../diagnostics" } +db = { path = "../db" } editor = { path = "../editor" } feedback = { path = "../feedback" } file_finder = { path = "../file_finder" } diff --git a/crates/zed/src/main.rs b/crates/zed/src/main.rs index 298e8ef8b9c50aff25f1b8bbf24c1b4f2559e37c..a9625bf78ee81e2d73e6a071f361e15dc12dd975 100644 --- a/crates/zed/src/main.rs +++ b/crates/zed/src/main.rs @@ -13,6 +13,7 @@ use client::{ http::{self, HttpClient}, UserStore, ZED_APP_VERSION, ZED_SECRET_CLIENT_TOKEN, }; +use db::kvp::KEY_VALUE_STORE; use futures::{ channel::{mpsc, oneshot}, FutureExt, SinkExt, StreamExt, @@ -43,9 +44,12 @@ use theme::ThemeRegistry; use util::StaffMode; use util::{channel::RELEASE_CHANNEL, paths, ResultExt, TryFutureExt}; use workspace::{ - self, item::ItemHandle, notifications::NotifyResultExt, AppState, OpenPaths, Welcome, Workspace, + self, item::ItemHandle, notifications::NotifyResultExt, AppState, NewFile, OpenPaths, Workspace, +}; +use zed::{ + self, build_window_options, initialize_workspace, languages, menus, WelcomeExperience, + FIRST_OPEN, }; -use zed::{self, build_window_options, initialize_workspace, languages, menus}; fn main() { let http = http::client(); @@ -258,9 +262,13 @@ async fn restore_or_create_workspace(mut cx: AsyncAppContext) { paths: location.paths().as_ref().clone(), }) }); + } else if matches!(KEY_VALUE_STORE.read_kvp(FIRST_OPEN), Ok(None)) { + cx.update(|cx| { + cx.dispatch_global_action(WelcomeExperience); + }); } else { cx.update(|cx| { - cx.dispatch_global_action(Welcome); + cx.dispatch_global_action(NewFile); }); } } diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index 2fbac3613ed3a6242c41db026e7b46b0d7f1aa50..75cdf0e687360e52b1e2af5e8eabf436bf0b0231 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -8,6 +8,7 @@ use breadcrumbs::Breadcrumbs; pub use client; use collab_ui::{CollabTitlebarItem, ToggleContactsMenu}; use collections::VecDeque; +use db::kvp::KEY_VALUE_STORE; pub use editor; use editor::{Editor, MultiBuffer}; @@ -34,7 +35,9 @@ use std::{borrow::Cow, env, path::Path, str, sync::Arc}; use util::{channel::ReleaseChannel, paths, ResultExt, StaffMode}; use uuid::Uuid; pub use workspace; -use workspace::{sidebar::SidebarSide, AppState, Restart, Workspace}; +use workspace::{sidebar::SidebarSide, AppState, Restart, Welcome, Workspace}; + +pub const FIRST_OPEN: &str = "first_open"; #[derive(Deserialize, Clone, PartialEq)] pub struct OpenBrowser { @@ -67,6 +70,7 @@ actions!( ResetBufferFontSize, InstallCommandLineInterface, ResetDatabase, + WelcomeExperience ] ); @@ -252,6 +256,25 @@ pub fn init(app_state: &Arc, cx: &mut gpui::MutableAppContext) { }, ); + cx.add_global_action(|_: &WelcomeExperience, cx| { + if !matches!(KEY_VALUE_STORE.read_kvp(FIRST_OPEN), Ok(None)) { + return; //noop, in case someone fires this from the command palette + } + + // Make a workspace, set it up with an open bottom dock and the welcome page + + cx.dispatch_global_action(Welcome); + + cx.background() + .spawn(async move { + KEY_VALUE_STORE + .write_kvp(FIRST_OPEN.to_string(), "false".to_string()) + .await + .log_err(); + }) + .detach(); + }); + activity_indicator::init(cx); call::init(app_state.client.clone(), app_state.user_store.clone(), cx); settings::KeymapFileContent::load_defaults(cx); From 5210be95feeb75ae801d90cbf354e2dd8c95ddd9 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Tue, 28 Feb 2023 22:11:58 -0800 Subject: [PATCH 09/93] Added welcome experience sketch Made toolbar hideable --- crates/db/src/db.rs | 11 +++++++++ crates/welcome/src/welcome.rs | 8 +++++-- crates/workspace/src/dock.rs | 40 +++++++++++++++++++------------ crates/workspace/src/item.rs | 8 +++++++ crates/workspace/src/pane.rs | 7 +++--- crates/workspace/src/toolbar.rs | 12 ++++++++++ crates/workspace/src/workspace.rs | 29 +++++++++++----------- crates/zed/src/zed.rs | 37 +++++++++++++++------------- styles/src/styleTree/workspace.ts | 2 +- 9 files changed, 103 insertions(+), 51 deletions(-) diff --git a/crates/db/src/db.rs b/crates/db/src/db.rs index f4d0dc1a469a272b0f2422e4eb0e88e33def510e..989dcf0af561999fb31e108f712b92eb9ff499d3 100644 --- a/crates/db/src/db.rs +++ b/crates/db/src/db.rs @@ -4,6 +4,7 @@ pub mod query; // Re-export pub use anyhow; use anyhow::Context; +use gpui::MutableAppContext; pub use indoc::indoc; pub use lazy_static; use parking_lot::{Mutex, RwLock}; @@ -17,6 +18,7 @@ use sqlez::domain::Migrator; use sqlez::thread_safe_connection::ThreadSafeConnection; use sqlez_macros::sql; use std::fs::create_dir_all; +use std::future::Future; use std::path::{Path, PathBuf}; use std::sync::atomic::{AtomicBool, Ordering}; use std::time::{SystemTime, UNIX_EPOCH}; @@ -237,6 +239,15 @@ macro_rules! define_connection { }; } +pub fn write_and_log(cx: &mut MutableAppContext, db_write: impl FnOnce() -> F + Send + 'static) +where + F: Future> + Send, +{ + cx.background() + .spawn(async move { db_write().await.log_err() }) + .detach() +} + #[cfg(test)] mod tests { use std::{fs, thread}; diff --git a/crates/welcome/src/welcome.rs b/crates/welcome/src/welcome.rs index 6985b700690a0eac970ffa7082dd0fa7e8c867df..5a166218ceb6df431de323de3a07fe43eb14c32d 100644 --- a/crates/welcome/src/welcome.rs +++ b/crates/welcome/src/welcome.rs @@ -14,7 +14,7 @@ pub fn init(cx: &mut MutableAppContext) { }) } -struct WelcomePage { +pub struct WelcomePage { _settings_subscription: Subscription, } @@ -98,7 +98,7 @@ impl View for WelcomePage { } impl WelcomePage { - fn new(cx: &mut ViewContext) -> Self { + pub fn new(cx: &mut ViewContext) -> Self { let handle = cx.weak_handle(); let settings_subscription = cx.observe_global::(move |cx| { @@ -163,4 +163,8 @@ impl Item for WelcomePage { ) .boxed() } + + fn show_toolbar(&self) -> bool { + false + } } diff --git a/crates/workspace/src/dock.rs b/crates/workspace/src/dock.rs index 2bd880828106cbfaf6dd6fb9797876b5d53ead0d..4281c04649ee12ea7ee6e02ee89784ca4620d22c 100644 --- a/crates/workspace/src/dock.rs +++ b/crates/workspace/src/dock.rs @@ -39,20 +39,24 @@ impl_internal_actions!(dock, [MoveDock, AddDefaultItemToDock]); pub fn init(cx: &mut MutableAppContext) { cx.add_action(Dock::focus_dock); cx.add_action(Dock::hide_dock); - cx.add_action(Dock::move_dock); + cx.add_action( + |workspace: &mut Workspace, &MoveDock(dock_anchor), cx: &mut ViewContext| { + Dock::move_dock(workspace, dock_anchor, true, cx); + }, + ); cx.add_action( |workspace: &mut Workspace, _: &AnchorDockRight, cx: &mut ViewContext| { - Dock::move_dock(workspace, &MoveDock(DockAnchor::Right), cx) + Dock::move_dock(workspace, DockAnchor::Right, true, cx); }, ); cx.add_action( |workspace: &mut Workspace, _: &AnchorDockBottom, cx: &mut ViewContext| { - Dock::move_dock(workspace, &MoveDock(DockAnchor::Bottom), cx) + Dock::move_dock(workspace, DockAnchor::Bottom, true, cx) }, ); cx.add_action( |workspace: &mut Workspace, _: &ExpandDock, cx: &mut ViewContext| { - Dock::move_dock(workspace, &MoveDock(DockAnchor::Expanded), cx) + Dock::move_dock(workspace, DockAnchor::Expanded, true, cx) }, ); cx.add_action( @@ -215,6 +219,7 @@ impl Dock { pub(crate) fn set_dock_position( workspace: &mut Workspace, new_position: DockPosition, + focus: bool, cx: &mut ViewContext, ) { workspace.dock.position = new_position; @@ -235,19 +240,23 @@ impl Dock { let pane = workspace.dock.pane.clone(); if pane.read(cx).items().next().is_none() { if let Some(item_to_add) = (workspace.dock.default_item_factory)(workspace, cx) { - Pane::add_item(workspace, &pane, item_to_add, true, true, None, cx); + Pane::add_item(workspace, &pane, item_to_add, focus, focus, None, cx); } else { workspace.dock.position = workspace.dock.position.hide(); } } else { - cx.focus(pane); + if focus { + cx.focus(pane); + } } } else if let Some(last_active_center_pane) = workspace .last_active_center_pane .as_ref() .and_then(|pane| pane.upgrade(cx)) { - cx.focus(last_active_center_pane); + if focus { + cx.focus(last_active_center_pane); + } } cx.emit(crate::Event::DockAnchorChanged); workspace.serialize_workspace(cx); @@ -255,11 +264,11 @@ impl Dock { } pub fn hide(workspace: &mut Workspace, cx: &mut ViewContext) { - Self::set_dock_position(workspace, workspace.dock.position.hide(), cx); + Self::set_dock_position(workspace, workspace.dock.position.hide(), true, cx); } - pub fn show(workspace: &mut Workspace, cx: &mut ViewContext) { - Self::set_dock_position(workspace, workspace.dock.position.show(), cx); + pub fn show(workspace: &mut Workspace, focus: bool, cx: &mut ViewContext) { + Self::set_dock_position(workspace, workspace.dock.position.show(), focus, cx); } pub fn hide_on_sidebar_shown( @@ -275,19 +284,20 @@ impl Dock { } fn focus_dock(workspace: &mut Workspace, _: &FocusDock, cx: &mut ViewContext) { - Self::set_dock_position(workspace, workspace.dock.position.show(), cx); + Self::set_dock_position(workspace, workspace.dock.position.show(), true, cx); } fn hide_dock(workspace: &mut Workspace, _: &HideDock, cx: &mut ViewContext) { - Self::set_dock_position(workspace, workspace.dock.position.hide(), cx); + Self::set_dock_position(workspace, workspace.dock.position.hide(), true, cx); } - fn move_dock( + pub fn move_dock( workspace: &mut Workspace, - &MoveDock(new_anchor): &MoveDock, + new_anchor: DockAnchor, + focus: bool, cx: &mut ViewContext, ) { - Self::set_dock_position(workspace, DockPosition::Shown(new_anchor), cx); + Self::set_dock_position(workspace, DockPosition::Shown(new_anchor), focus, cx); } pub fn render( diff --git a/crates/workspace/src/item.rs b/crates/workspace/src/item.rs index a80b9f8d83d9dc4d407b337a944537143e24581e..b55c9942f8b51707c3b550545971cc57e047b2ce 100644 --- a/crates/workspace/src/item.rs +++ b/crates/workspace/src/item.rs @@ -151,6 +151,9 @@ pub trait Item: View { "deserialize() must be implemented if serialized_item_kind() returns Some(_)" ) } + fn show_toolbar(&self) -> bool { + true + } } pub trait ItemHandle: 'static + fmt::Debug { @@ -213,6 +216,7 @@ pub trait ItemHandle: 'static + fmt::Debug { fn breadcrumb_location(&self, cx: &AppContext) -> ToolbarItemLocation; fn breadcrumbs(&self, theme: &Theme, cx: &AppContext) -> Option>; fn serialized_item_kind(&self) -> Option<&'static str>; + fn show_toolbar(&self, cx: &AppContext) -> bool; } pub trait WeakItemHandle { @@ -591,6 +595,10 @@ impl ItemHandle for ViewHandle { fn serialized_item_kind(&self) -> Option<&'static str> { T::serialized_item_kind() } + + fn show_toolbar(&self, cx: &AppContext) -> bool { + self.read(cx).show_toolbar() + } } impl From> for AnyViewHandle { diff --git a/crates/workspace/src/pane.rs b/crates/workspace/src/pane.rs index 98fcac664c069fa5c22c233e54a2f5b0a96a1c25..235df0202d6fc3fc6f4546596385fee28b0647bf 100644 --- a/crates/workspace/src/pane.rs +++ b/crates/workspace/src/pane.rs @@ -1485,11 +1485,12 @@ impl View for Pane { cx, { let toolbar = self.toolbar.clone(); + let toolbar_hidden = toolbar.read(cx).hidden(); move |_, cx| { Flex::column() - .with_child( - ChildView::new(&toolbar, cx).expanded().boxed(), - ) + .with_children((!toolbar_hidden).then(|| { + ChildView::new(&toolbar, cx).expanded().boxed() + })) .with_child( ChildView::new(active_item, cx) .flex(1., true) diff --git a/crates/workspace/src/toolbar.rs b/crates/workspace/src/toolbar.rs index 7443f19003fabcf14771655a39d51bd07f8a6813..df10db91a05dbd24a31d6122eb3a39ee6ca4de2f 100644 --- a/crates/workspace/src/toolbar.rs +++ b/crates/workspace/src/toolbar.rs @@ -42,6 +42,7 @@ pub enum ToolbarItemLocation { pub struct Toolbar { active_pane_item: Option>, + hidden: bool, pane: WeakViewHandle, items: Vec<(Box, ToolbarItemLocation)>, } @@ -211,6 +212,7 @@ impl Toolbar { active_pane_item: None, pane, items: Default::default(), + hidden: false, } } @@ -243,6 +245,12 @@ impl Toolbar { cx: &mut ViewContext, ) { self.active_pane_item = pane_item.map(|item| item.boxed_clone()); + self.hidden = self + .active_pane_item + .as_ref() + .map(|item| !item.show_toolbar(cx)) + .unwrap_or(false); + for (toolbar_item, current_location) in self.items.iter_mut() { let new_location = toolbar_item.set_active_pane_item(pane_item, cx); if new_location != *current_location { @@ -257,6 +265,10 @@ impl Toolbar { .iter() .find_map(|(item, _)| item.to_any().downcast()) } + + pub fn hidden(&self) -> bool { + self.hidden + } } impl ToolbarItemViewHandle for ViewHandle { diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index 31960fbc1ec7751a147ecfcf788e26dd33ab1a0d..442d28579fc1be8358cf322fa3f0c264d9cbdec3 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -197,20 +197,12 @@ pub fn init(app_state: Arc, cx: &mut MutableAppContext) { } } }); - cx.add_global_action({ - let app_state = Arc::downgrade(&app_state); - move |_: &Welcome, cx: &mut MutableAppContext| { - if let Some(app_state) = app_state.upgrade() { - open_new(&app_state, cx).detach(); - } - } - }); cx.add_global_action({ let app_state = Arc::downgrade(&app_state); move |_: &NewWindow, cx: &mut MutableAppContext| { if let Some(app_state) = app_state.upgrade() { - open_new(&app_state, cx).detach(); + open_new(&app_state, cx, |_, cx| cx.dispatch_action(NewFile)).detach(); } } }); @@ -1514,7 +1506,7 @@ impl Workspace { self.active_item_path_changed(cx); if &pane == self.dock_pane() { - Dock::show(self, cx); + Dock::show(self, true, cx); } else { self.last_active_center_pane = Some(pane.downgrade()); if self.dock.is_anchored_at(DockAnchor::Expanded) { @@ -2527,7 +2519,12 @@ impl Workspace { // the focus the dock generates start generating alternating // focus due to the deferred execution each triggering each other cx.after_window_update(move |workspace, cx| { - Dock::set_dock_position(workspace, serialized_workspace.dock_position, cx); + Dock::set_dock_position( + workspace, + serialized_workspace.dock_position, + true, + cx, + ); }); cx.notify(); @@ -2859,14 +2856,18 @@ pub fn open_paths( }) } -pub fn open_new(app_state: &Arc, cx: &mut MutableAppContext) -> Task<()> { +pub fn open_new( + app_state: &Arc, + cx: &mut MutableAppContext, + init: impl FnOnce(&mut Workspace, &mut ViewContext) + 'static, +) -> Task<()> { let task = Workspace::new_local(Vec::new(), app_state.clone(), cx); cx.spawn(|mut cx| async move { let (workspace, opened_paths) = task.await; - workspace.update(&mut cx, |_, cx| { + workspace.update(&mut cx, |workspace, cx| { if opened_paths.is_empty() { - cx.dispatch_action(Welcome); + init(workspace, cx) } }) }) diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index 75cdf0e687360e52b1e2af5e8eabf436bf0b0231..5d13d41bba066ca041b9f5ffdc76a4a193cd19ba 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -35,7 +35,7 @@ use std::{borrow::Cow, env, path::Path, str, sync::Arc}; use util::{channel::ReleaseChannel, paths, ResultExt, StaffMode}; use uuid::Uuid; pub use workspace; -use workspace::{sidebar::SidebarSide, AppState, Restart, Welcome, Workspace}; +use workspace::{dock::Dock, open_new, sidebar::SidebarSide, AppState, Restart, Workspace}; pub const FIRST_OPEN: &str = "first_open"; @@ -256,23 +256,27 @@ pub fn init(app_state: &Arc, cx: &mut gpui::MutableAppContext) { }, ); - cx.add_global_action(|_: &WelcomeExperience, cx| { - if !matches!(KEY_VALUE_STORE.read_kvp(FIRST_OPEN), Ok(None)) { - return; //noop, in case someone fires this from the command palette - } - - // Make a workspace, set it up with an open bottom dock and the welcome page - - cx.dispatch_global_action(Welcome); + cx.add_global_action({ + let app_state = app_state.clone(); + move |_: &WelcomeExperience, cx| { + if !matches!(KEY_VALUE_STORE.read_kvp(FIRST_OPEN), Ok(None)) { + return; //noop, in case someone fires this from the command palette + } - cx.background() - .spawn(async move { - KEY_VALUE_STORE - .write_kvp(FIRST_OPEN.to_string(), "false".to_string()) - .await - .log_err(); + open_new(&app_state, cx, |workspace, cx| { + workspace.toggle_sidebar(SidebarSide::Left, cx); + let welcome_page = cx.add_view(|cx| welcome::WelcomePage::new(cx)); + workspace.add_item(Box::new(welcome_page.clone()), cx); + Dock::move_dock(workspace, settings::DockAnchor::Bottom, false, cx); + cx.focus(welcome_page); + cx.notify(); }) .detach(); + + db::write_and_log(cx, || { + KEY_VALUE_STORE.write_kvp(FIRST_OPEN.to_string(), "false".to_string()) + }); + } }); activity_indicator::init(cx); @@ -881,7 +885,8 @@ mod tests { #[gpui::test] async fn test_new_empty_workspace(cx: &mut TestAppContext) { let app_state = init(cx); - cx.update(|cx| open_new(&app_state, cx)).await; + cx.update(|cx| open_new(&app_state, cx, |_, cx| cx.dispatch_action(NewFile))) + .await; let window_id = *cx.window_ids().first().unwrap(); let workspace = cx.root_view::(window_id).unwrap(); diff --git a/styles/src/styleTree/workspace.ts b/styles/src/styleTree/workspace.ts index f9f49e3c7df14b5ccf14a9322a1a461c1c153917..c758e0227e2413ed86a15a10c28a22499d59131d 100644 --- a/styles/src/styleTree/workspace.ts +++ b/styles/src/styleTree/workspace.ts @@ -248,7 +248,7 @@ export default function workspace(colorScheme: ColorScheme) { }, dock: { initialSizeRight: 640, - initialSizeBottom: 480, + initialSizeBottom: 300, wash_color: withOpacity(background(colorScheme.highest), 0.5), panel: { border: border(colorScheme.middle), From 62aeb6b8b390ffe5c547c544726f5813778854e7 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Tue, 28 Feb 2023 22:33:12 -0800 Subject: [PATCH 10/93] Added background to welcome page --- crates/welcome/src/welcome.rs | 115 ++++++++++++++++++++-------------- 1 file changed, 68 insertions(+), 47 deletions(-) diff --git a/crates/welcome/src/welcome.rs b/crates/welcome/src/welcome.rs index 5a166218ceb6df431de323de3a07fe43eb14c32d..afb38385a4a21b9bed94b10c96570f30e51000ae 100644 --- a/crates/welcome/src/welcome.rs +++ b/crates/welcome/src/welcome.rs @@ -1,6 +1,7 @@ use gpui::{ color::Color, - elements::{Empty, Flex, Label, MouseEventHandler, ParentElement, Svg}, + elements::{Canvas, Empty, Flex, Label, MouseEventHandler, ParentElement, Stack, Svg}, + geometry::rect::RectF, Element, ElementBox, Entity, MutableAppContext, RenderContext, Subscription, View, ViewContext, }; use settings::{settings_file::SettingsFile, Settings, SettingsFileContent}; @@ -39,60 +40,80 @@ impl View for WelcomePage { enum Metrics {} enum Diagnostics {} - Flex::column() - .with_children([ - Flex::row() - .with_children([ - Svg::new("icons/terminal_16.svg") - .with_color(Color::red()) - .constrained() - .with_width(100.) - .with_height(100.) - .aligned() - .contained() - .boxed(), - Label::new("Zed", theme.editor.hover_popover.prose.clone()).boxed(), - ]) - .boxed(), - Label::new( - "Code at the speed of thought", - theme.editor.hover_popover.prose.clone(), - ) + let background = theme.editor.background; + + Stack::new() + .with_child( + Canvas::new(move |bounds, visible_bounds, cx| { + let visible_bounds = bounds.intersection(visible_bounds).unwrap_or_default(); + + cx.paint_layer(Some(visible_bounds), |cx| { + cx.scene.push_quad(gpui::Quad { + bounds: RectF::new(bounds.origin(), bounds.size()), + background: Some(background), + ..Default::default() + }) + }) + }) .boxed(), - Flex::row() - .with_children([ - self.render_settings_checkbox::( - &theme.welcome.checkbox, - metrics, - cx, - |content, checked| { - content.telemetry.set_metrics(checked); - }, - ), - Label::new( - "Do you want to send telemetry?", - theme.editor.hover_popover.prose.clone(), - ) - .boxed(), - ]) - .boxed(), - Flex::row() + ) + .with_child( + Flex::column() .with_children([ - self.render_settings_checkbox::( - &theme.welcome.checkbox, - diagnostics, - cx, - |content, checked| content.telemetry.set_diagnostics(checked), - ), + Flex::row() + .with_children([ + Svg::new("icons/terminal_16.svg") + .with_color(Color::red()) + .constrained() + .with_width(100.) + .with_height(100.) + .aligned() + .contained() + .boxed(), + Label::new("Zed", theme.editor.hover_popover.prose.clone()).boxed(), + ]) + .boxed(), Label::new( - "Send crash reports", + "Code at the speed of thought", theme.editor.hover_popover.prose.clone(), ) .boxed(), + Flex::row() + .with_children([ + self.render_settings_checkbox::( + &theme.welcome.checkbox, + metrics, + cx, + |content, checked| { + content.telemetry.set_metrics(checked); + }, + ), + Label::new( + "Do you want to send telemetry?", + theme.editor.hover_popover.prose.clone(), + ) + .boxed(), + ]) + .boxed(), + Flex::row() + .with_children([ + self.render_settings_checkbox::( + &theme.welcome.checkbox, + diagnostics, + cx, + |content, checked| content.telemetry.set_diagnostics(checked), + ), + Label::new( + "Send crash reports", + theme.editor.hover_popover.prose.clone(), + ) + .boxed(), + ]) + .boxed(), ]) + .aligned() .boxed(), - ]) - .aligned() + ) .boxed() } } From 9dee2ca2be3606f994cba67f1a097a454268bf4b Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Wed, 1 Mar 2023 20:42:01 -0800 Subject: [PATCH 11/93] WIP --- crates/project_panel/src/project_panel.rs | 182 ++++++++++++++----- crates/terminal_view/src/terminal_element.rs | 2 +- crates/welcome/src/welcome.rs | 12 +- 3 files changed, 143 insertions(+), 53 deletions(-) diff --git a/crates/project_panel/src/project_panel.rs b/crates/project_panel/src/project_panel.rs index 4b3c5b7bc53a452b8b6d11ec41e7e41b8228a7f3..1cefc558f00d3f5e3c4f3c73987a42f8b4755652 100644 --- a/crates/project_panel/src/project_panel.rs +++ b/crates/project_panel/src/project_panel.rs @@ -5,9 +5,11 @@ use futures::stream::StreamExt; use gpui::{ actions, anyhow::{anyhow, Result}, + color::Color, elements::{ - AnchorCorner, ChildView, ConstrainedBox, ContainerStyle, Empty, Flex, Label, - MouseEventHandler, ParentElement, ScrollTarget, Stack, Svg, UniformList, UniformListState, + AnchorCorner, Canvas, ChildView, ConstrainedBox, ContainerStyle, Empty, Flex, + KeystrokeLabel, Label, MouseEventHandler, ParentElement, ScrollTarget, Stack, Svg, + UniformList, UniformListState, }, geometry::vector::Vector2F, impl_internal_actions, @@ -1262,54 +1264,134 @@ impl View for ProjectPanel { let padding = std::mem::take(&mut container_style.padding); let last_worktree_root_id = self.last_worktree_root_id; - Stack::new() - .with_child( - MouseEventHandler::::new(0, cx, |_, cx| { - UniformList::new( - self.list.clone(), - self.visible_entries - .iter() - .map(|(_, worktree_entries)| worktree_entries.len()) - .sum(), - cx, - move |this, range, items, cx| { - let theme = cx.global::().theme.clone(); - let mut dragged_entry_destination = - this.dragged_entry_destination.clone(); - this.for_each_visible_entry(range, cx, |id, details, cx| { - items.push(Self::render_entry( - id, - details, - &this.filename_editor, - &mut dragged_entry_destination, - &theme.project_panel, - cx, - )); - }); - this.dragged_entry_destination = dragged_entry_destination; - }, - ) - .with_padding_top(padding.top) - .with_padding_bottom(padding.bottom) - .contained() - .with_style(container_style) - .expanded() - .boxed() - }) - .on_down(MouseButton::Right, move |e, cx| { - // When deploying the context menu anywhere below the last project entry, - // act as if the user clicked the root of the last worktree. - if let Some(entry_id) = last_worktree_root_id { - cx.dispatch_action(DeployContextMenu { - entry_id, - position: e.position, - }) - } - }) - .boxed(), - ) - .with_child(ChildView::new(&self.context_menu, cx).boxed()) - .boxed() + let has_worktree = self.visible_entries.len() != 0; + + if has_worktree { + Stack::new() + .with_child( + MouseEventHandler::::new(0, cx, |_, cx| { + UniformList::new( + self.list.clone(), + self.visible_entries + .iter() + .map(|(_, worktree_entries)| worktree_entries.len()) + .sum(), + cx, + move |this, range, items, cx| { + let theme = cx.global::().theme.clone(); + let mut dragged_entry_destination = + this.dragged_entry_destination.clone(); + this.for_each_visible_entry(range, cx, |id, details, cx| { + items.push(Self::render_entry( + id, + details, + &this.filename_editor, + &mut dragged_entry_destination, + &theme.project_panel, + cx, + )); + }); + this.dragged_entry_destination = dragged_entry_destination; + }, + ) + .with_padding_top(padding.top) + .with_padding_bottom(padding.bottom) + .contained() + .with_style(container_style) + .expanded() + .boxed() + }) + .on_down(MouseButton::Right, move |e, cx| { + // When deploying the context menu anywhere below the last project entry, + // act as if the user clicked the root of the last worktree. + if let Some(entry_id) = last_worktree_root_id { + cx.dispatch_action(DeployContextMenu { + entry_id, + position: e.position, + }) + } + }) + .boxed(), + ) + .with_child(ChildView::new(&self.context_menu, cx).boxed()) + .boxed() + } else { + let parent_view_id = cx.handle().id(); + Stack::new() + .with_child( + MouseEventHandler::::new(1, cx, |_, cx| { + Stack::new() + .with_child( + Canvas::new(|bounds, _visible_bounds, cx| { + cx.scene.push_quad(gpui::Quad { + bounds, + background: Some(Color::red()), + ..Default::default() + }) + }) + .boxed(), + ) + .with_child( + MouseEventHandler::::new(2, cx, |state, cx| { + let style = &cx + .global::() + .theme + .search + .option_button + .style_for(state, false); + + let context_menu_item = cx + .global::() + .theme + .context_menu + .clone() + .item + .style_for(state, true) + .clone(); + + Flex::row() + .with_child( + Label::new( + "Open a new project!".to_string(), + context_menu_item.label.clone(), + ) + .contained() + .boxed(), + ) + .with_child({ + KeystrokeLabel::new( + cx.window_id(), + parent_view_id, + Box::new(workspace::Open), + context_menu_item.keystroke.container, + context_menu_item.keystroke.text.clone(), + ) + .flex_float() + .boxed() + }) + .contained() + .with_style(style.container) + .aligned() + .top() + .constrained() + .with_width(100.) + .with_height(20.) + .boxed() + }) + .on_click(MouseButton::Left, move |_, cx| { + cx.dispatch_action(workspace::Open) + }) + .with_cursor_style(CursorStyle::PointingHand) + .boxed(), + ) + .boxed() + }) + // TODO is this nescessary? + .on_click(MouseButton::Left, |_, cx| cx.focus_parent_view()) + .boxed(), + ) + .boxed() + } } fn keymap_context(&self, _: &AppContext) -> KeymapContext { diff --git a/crates/terminal_view/src/terminal_element.rs b/crates/terminal_view/src/terminal_element.rs index 08ed3ecc2d1da04352dac73a9438a5f3087c8b74..5d03d6304e28ed93d334c308bd5c7d11dc526b07 100644 --- a/crates/terminal_view/src/terminal_element.rs +++ b/crates/terminal_view/src/terminal_element.rs @@ -720,7 +720,7 @@ impl Element for TerminalElement { cx.paint_layer(clip_bounds, |cx| { let origin = bounds.origin() + vec2f(layout.size.cell_width, 0.); - //Elements are ephemeral, only at paint time do we know what could be clicked by a mouse + // Elements are ephemeral, only at paint time do we know what could be clicked by a mouse self.attach_mouse_handlers(origin, self.view.id(), visible_bounds, layout.mode, cx); cx.scene.push_cursor_region(gpui::CursorRegion { diff --git a/crates/welcome/src/welcome.rs b/crates/welcome/src/welcome.rs index afb38385a4a21b9bed94b10c96570f30e51000ae..54898f92c845c06d2b29479baac015971bd6fe1a 100644 --- a/crates/welcome/src/welcome.rs +++ b/crates/welcome/src/welcome.rs @@ -2,7 +2,8 @@ use gpui::{ color::Color, elements::{Canvas, Empty, Flex, Label, MouseEventHandler, ParentElement, Stack, Svg}, geometry::rect::RectF, - Element, ElementBox, Entity, MutableAppContext, RenderContext, Subscription, View, ViewContext, + Element, ElementBox, Entity, MouseRegion, MutableAppContext, RenderContext, Subscription, View, + ViewContext, }; use settings::{settings_file::SettingsFile, Settings, SettingsFileContent}; use theme::CheckboxStyle; @@ -29,6 +30,7 @@ impl View for WelcomePage { } fn render(&mut self, cx: &mut gpui::RenderContext<'_, Self>) -> ElementBox { + let self_handle = cx.handle(); let settings = cx.global::(); let theme = settings.theme.clone(); @@ -44,6 +46,7 @@ impl View for WelcomePage { Stack::new() .with_child( + // TODO: Can this be moved into the pane? Canvas::new(move |bounds, visible_bounds, cx| { let visible_bounds = bounds.intersection(visible_bounds).unwrap_or_default(); @@ -53,7 +56,12 @@ impl View for WelcomePage { background: Some(background), ..Default::default() }) - }) + }); + + cx.scene.push_mouse_region( + MouseRegion::new::(self_handle.id(), 0, visible_bounds) + .on_down(gpui::MouseButton::Left, |_, cx| cx.focus_parent_view()), + ); }) .boxed(), ) From f89f33347de1289c0d78cf9cb1b68fe5b1199765 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Mon, 6 Mar 2023 09:58:07 -0800 Subject: [PATCH 12/93] Added CTA buttons to welcome experience Co-authored-by: Nathan --- Cargo.lock | 1 + crates/theme/src/theme.rs | 1 + crates/welcome/Cargo.toml | 1 + crates/welcome/src/welcome.rs | 36 ++++++++++- styles/src/styleTree/welcome.ts | 111 +++++++++++++++++++------------- 5 files changed, 102 insertions(+), 48 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c8124fcc3a180d2159a7bd8e5a690986f7dfa527..c25656bfa9300a42a5a752b2e47bf4abda7f3348 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8024,6 +8024,7 @@ dependencies = [ "project", "settings", "theme", + "theme_selector", "util", "workspace", ] diff --git a/crates/theme/src/theme.rs b/crates/theme/src/theme.rs index 87b9d9845a314d6db5a63c280b417c43a6dc43cf..ded5c54f832ba53cbcc9c4ab998ed38122b38631 100644 --- a/crates/theme/src/theme.rs +++ b/crates/theme/src/theme.rs @@ -854,6 +854,7 @@ pub struct FeedbackStyle { #[derive(Clone, Deserialize, Default)] pub struct WelcomeStyle { pub checkbox: CheckboxStyle, + pub button: Interactive, } #[derive(Clone, Deserialize, Default)] diff --git a/crates/welcome/Cargo.toml b/crates/welcome/Cargo.toml index 3e450e2312794188f3ba9e3401fe80affeab6ad9..e1231ad5f631a11dfdad9bd77341b14207b572b5 100644 --- a/crates/welcome/Cargo.toml +++ b/crates/welcome/Cargo.toml @@ -18,5 +18,6 @@ gpui = { path = "../gpui" } project = { path = "../project" } settings = { path = "../settings" } theme = { path = "../theme" } +theme_selector = { path = "../theme_selector" } util = { path = "../util" } workspace = { path = "../workspace" } \ No newline at end of file diff --git a/crates/welcome/src/welcome.rs b/crates/welcome/src/welcome.rs index 54898f92c845c06d2b29479baac015971bd6fe1a..7bf6c263023470ca784f7d4f1e05283a9926cfd3 100644 --- a/crates/welcome/src/welcome.rs +++ b/crates/welcome/src/welcome.rs @@ -1,12 +1,14 @@ +use std::borrow::Cow; + use gpui::{ color::Color, elements::{Canvas, Empty, Flex, Label, MouseEventHandler, ParentElement, Stack, Svg}, geometry::rect::RectF, - Element, ElementBox, Entity, MouseRegion, MutableAppContext, RenderContext, Subscription, View, - ViewContext, + Action, Element, ElementBox, Entity, MouseButton, MouseRegion, MutableAppContext, + RenderContext, Subscription, View, ViewContext, }; use settings::{settings_file::SettingsFile, Settings, SettingsFileContent}; -use theme::CheckboxStyle; +use theme::{CheckboxStyle, ContainedText, Interactive}; use workspace::{item::Item, Welcome, Workspace}; pub fn init(cx: &mut MutableAppContext) { @@ -86,6 +88,8 @@ impl View for WelcomePage { theme.editor.hover_popover.prose.clone(), ) .boxed(), + self.render_cta_button(2, "Choose a theme", theme_selector::Toggle, cx), + self.render_cta_button(3, "Choose a keymap", theme_selector::Toggle, cx), Flex::row() .with_children([ self.render_settings_checkbox::( @@ -141,6 +145,32 @@ impl WelcomePage { } } + fn render_cta_button( + &self, + region_id: usize, + label: L, + action: A, + cx: &mut RenderContext, + ) -> ElementBox + where + L: Into>, + A: 'static + Action + Clone, + { + let theme = cx.global::().theme.clone(); + MouseEventHandler::::new(region_id, cx, |state, _| { + let style = theme.welcome.button.style_for(state, false); + Label::new(label, style.text.clone()) + .contained() + .with_style(style.container) + .boxed() + }) + .on_click(MouseButton::Left, move |_, cx| { + cx.dispatch_action(action.clone()) + }) + .aligned() + .boxed() + } + fn render_settings_checkbox( &self, style: &CheckboxStyle, diff --git a/styles/src/styleTree/welcome.ts b/styles/src/styleTree/welcome.ts index 6085782afd009722784c5f70e6a835bb3fe0f1ef..114ff0b7df69e12a0229698c3232c995e1edde2f 100644 --- a/styles/src/styleTree/welcome.ts +++ b/styles/src/styleTree/welcome.ts @@ -1,55 +1,76 @@ import { ColorScheme } from "../themes/common/colorScheme"; -import { border } from "./components"; +import { border, background, text } from "./components"; + export default function welcome(colorScheme: ColorScheme) { - let layer = colorScheme.highest; + let layer = colorScheme.highest; - // TODO - let checkboxBase = { - cornerRadius: 4, - padding: { - left: 8, - right: 8, - top: 4, - bottom: 4, - }, - shadow: colorScheme.popoverShadow, - border: border(layer), - margin: { - left: -8, - }, - }; + // TODO + let checkboxBase = { + cornerRadius: 4, + padding: { + left: 8, + right: 8, + top: 4, + bottom: 4, + }, + shadow: colorScheme.popoverShadow, + border: border(layer), + margin: { + left: -8, + }, + }; - return { - checkbox: { - width: 9, - height: 9, - default: { - ...checkboxBase, - background: colorScheme.ramps.blue(0.5).hex(), - }, - checked: { - ...checkboxBase, - background: colorScheme.ramps.red(0.5).hex(), - }, - hovered: { - ...checkboxBase, - background: colorScheme.ramps.blue(0.5).hex(), + return { + button: { + background: background(layer), + border: border(layer), + cornerRadius: 6, + margin: { + top: 1, + }, + padding: { + top: 1, + bottom: 1, + left: 7, + right: 7, + }, + ...text(layer, "sans", "variant", { size: "xs" }), + hover: { + ...text(layer, "sans", "hovered", { size: "xs" }), + background: background(layer, "hovered"), + border: border(layer, "hovered"), + }, + }, + checkbox: { + width: 9, + height: 9, + default: { + ...checkboxBase, + background: colorScheme.ramps.blue(0.5).hex(), + }, + checked: { + ...checkboxBase, + background: colorScheme.ramps.red(0.5).hex(), + }, + hovered: { + ...checkboxBase, + background: colorScheme.ramps.blue(0.5).hex(), - border: { - color: colorScheme.ramps.green(0.5).hex(), - width: 1, - } - }, - hoveredAndChecked: { - ...checkboxBase, - background: colorScheme.ramps.red(0.5).hex(), - border: { - color: colorScheme.ramps.green(0.5).hex(), - width: 1, - } - } + border: { + color: colorScheme.ramps.green(0.5).hex(), + width: 1, + } + }, + hoveredAndChecked: { + ...checkboxBase, + background: colorScheme.ramps.red(0.5).hex(), + border: { + color: colorScheme.ramps.green(0.5).hex(), + width: 1, } + } } + } } \ No newline at end of file From 4c179875ab5b120a871bfb853aa6969fa8779478 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Mon, 6 Mar 2023 10:39:35 -0800 Subject: [PATCH 13/93] Add png image loading to gpui add zed logo into welcome experience Co-authored-by: Nathan --- assets/images/zed-logo-90x90.png | Bin 0 -> 12413 bytes crates/collab_ui/src/collab_titlebar_item.rs | 2 +- crates/collab_ui/src/contact_finder.rs | 2 +- crates/collab_ui/src/contact_list.rs | 6 +- .../src/incoming_call_notification.rs | 2 +- crates/collab_ui/src/notifications.rs | 2 +- .../src/project_shared_notification.rs | 2 +- crates/gpui/src/assets.rs | 21 ++++++- crates/gpui/src/elements/image.rs | 56 +++++++++++++----- crates/project_panel/src/project_panel.rs | 2 +- crates/welcome/src/welcome.rs | 14 ++--- 11 files changed, 76 insertions(+), 33 deletions(-) create mode 100644 assets/images/zed-logo-90x90.png diff --git a/assets/images/zed-logo-90x90.png b/assets/images/zed-logo-90x90.png new file mode 100644 index 0000000000000000000000000000000000000000..17f92d2c1afbb8459fd31bfdc7ace50a412ce0a8 GIT binary patch literal 12413 zcmZ{K2UJthvUcbK0tyP!QKU%;5G2%qq9P(iKza!!v;dLNds7hU9i${k@6x4%C^hsF ziZp=$0i^f#)R72F8#@>P@G>+ZiA+m#jn;o!IEK4qcc*AV4ML7baKs)<>J$9SJV?=iDbt)KYzEuONsoZlqIlq7V-#d zsY1oPtmVj|mZI1n#t3_(D!6 z8X|uyi1-MKDU@s6dxmE;>C zc0pX`J@smE(jXZ-6!7F0?Nh~jABD``Cv(<(r2GD&F$VDPX6RGe7>kEgF&q>Y_bYDl zJ$V&FVIi#%!SXEffmO8fOKBwg+B46X+AfAWA;aq2w*LBPx;NrIPZWmkIg@@4?tij3 z_|*BXex!Eh*&yluO;3`h2v;<4$d_ea>)n)uc^YeE#NzMoj!NIO(r(t?(+THqf4gAo z*!NBQmx>|TpSyoR86U0Y_1vW!c_8=L!x-jQ<{1`se)Dg8ZBrdP9j6|vdb3|j2dED6 zOwh{QkaV(pZSv)|F89`f9c5sx{HQH^nku2({JJ+k1epp%SFdzKhY*#%o_T8dj@ zUSit?JWn@M-9f+Cd>?-jKNg=JZ`t$s6&U7U_@p}9^No2v<7mz((pK<5=HT{0`lnBy zLO(UU%KoIwWs+mK?BDY|K{a7OOyx6GgmS8?=AibF>xk;epOM+2HD}6tplqm6UfCC& zk%3{*SSeoAIjU~_CLq-x9BkI_mv z5~M2T@blZ0Be=t7l(B5Fh;x{4ykMlRWbb)W4l_Enph3I#%~3g<@xTk92BLIUyJ^p} ztOL~P70D0|Wb?B=C-Tvndm;DAFW{2;qUiL3G??@WsYZ|rsTGwmqb>6(ljXfqu#C+F z{D<(aI4yGtSPHfunDg`Z*9zU`Vy9w=xz8fh{KJmxqWB^KopPLR9ATVPTxYJ9W{pkZ zn&$}p2n57g$!AH~XNzG=*2GNW)^N;y27Pk+y81s11Zu6T+#L$cyDKr3#pT`>&ue$f zKbyaWx%7Uv?yKpqnlyv#Pbjy2y7Rz?1<{|dI_0olunt%!1zrL#OHDDTn6|8Ku;Z2vY>M?6 zN}vC;(){D%+nE)O4ozL>{U|xvO&O5vktYOYC#fgqv9crtqysi%UCXEuiEb4~1GB7< z4v07E5h|}axB2OuQL`)yT$R*{eWe-|gu;}~ZgFCR8a{eWv9GW%nQY9_qZw~8tKZ&! zIQURl@GJLMU>BG5lfgCU(|6X}Q}YcnL>c}%ee0BtlzMlNLhBnVA z(rHCuGx3U=eR;2P#e)?jfZj&Oi#K{dO5W~#5E^qkCLw0v3riOLi|QAkFILaDA}((& zGE_?8OpD(ZKd9kS6?E`4botfkesw&29Qi(!JdC#VA)f0KU25!0B}b)(*wZ|c*VDo! zUiH2EU)J0#b^DXSi^H#*QuIJ-7>(4QC>M#8Xckl>_=I0B&E)5n+Cq+<>KffU5@r(M zhvx4G-;HCE^0h|e@Co{#Pi6Y}?Tz#i^=h7ar~D#1hWCBrZl{$CE}C1q!#AP14>gevH47UamD4#j!w+maS)wGFar@m*VGYRWG)74kB)2$=(OX?UUv+1k z=ZZGY_cJs2Xj>-2Bi2J_Wg255(!v82-bx}lCJ7`Fq>Nw?GMcFSSZRG`X5rZLJCQ3_ znIg$~g=~3C@0HQ#x_vBRNZ@ebQSa}h#|%t&a15>&xAqlOVr*lISN|XfmZyDxT=8C( z+ke>mq{83KKp6&1l8BE_@HXPp^*G__MD_SF879;h+E=gROW+^j58;1`5A+)Hw6es? zs^By6E>!D!>tWcIIbnEvPK6R|T3iGCNZd6(BmrzMI$dQsg8j7rX*$6-!6o$oTsCp; z81}9=qNLdXUdw35KY6%pwKH&3LuQZ2ugHHi{p43n!{TKBxAc;huYLuyIkiO=*xH%c z8CI_^hiOHwMWwSvEp9GU`dRsFGhm;&gNw_vRNGD4TC5E=fyJNb6A_S_o4wJAcVE5N z^l)K{6Q?MS1>wV(qk~VVd?MB&SXDw*HWd{jYs9?7vFw#{HD}*;c6#Xad9+d483Hnr z?vJ*#u58xUbgYK^ovSgn9`51`8zoLLD^vX;87=Pjx4%zntF9M>88bwg?0$3J7d=BR z-o^4$=@^xcU*UJ*KB;hn_Q$nw73@qIxK_C%i6xRx!)~bAV*VcP}z`I&oO-vZ(X5vz4*t_sxI6 z72qI*PVJJc3pI#^-@RkqbETt^jDd}T5|iI8`!_KcuTJ$Z`%Vq^js~}) zNGr+6a=aP+-0!rSe#*@yY@DHzS0jc(LBuXoU9V*Yy1M*Yh1>jo$JBZ08WPxwfW(*_ z)reSHM<1}u_c1`N1wQSNj85tmWbJKj7egKfPqcg&le{JVV%ESgn&v7xM)DHqb2Snu zx<0qj0^ovBQnNNbeRy5N8p3pyELBthkFMz(0Ad1C0MRu?03f_R(f*4jxTbmk!w<0m z5dT950DxRy0RTcY;lDXmXrlkne}(TGBnPimYHYN0opn`SOPM3=g-k6FW-uXl`*(j8 z05a}U*Q7nn*_6ZG-p;{E%3b!sKQyGS>A!5?1CD>FIKyQh=&Go5C?Jq94sju2A>juQ z3Jwkq8Ki}!l*Y3c|AJrN$v&`lc77)X1iHDo3AurU5J)Sah@_+>P*@ZwDk^xbA?W1c z;B4wH=-|Zp&q4lcoM$j6bEM5XXB&hA$KP>H%@8imvJW2oHT3V}pME;qSpLV7gVVpl zx(*QdR{|6f5(fTnFqpf|{{j0e`6uijasAVr%-_MJ6cG0BkT55wYquaGGXF5}|MC9g z-aqv4DjE35<>Br0*eL!9vCS-d!pq|u$itBC7|bt%?nwuU#|HP z`xDkqUDu?DOaTg4noV!2wI0)17&rTuHwpKelJVaZy+^Jr`%;(w#t#93`>n(KA4!-O zQ$Cnjw2q{iSX}O2t}lgleZtR#$%8sd+WXPcA5rMla2kgY&^7V9ILP~Xu~#9- ze^y{;;ktF;qIBGyptL@rpAmQXIT_;x_r}%#&k9`#=G zpuBgxbv{Iv>M8Kb`#xfHg(=j!B+HkDjPnl|_zFp8`4AkOmA9)B)&ou|X^;6~auHna zi>EA0%yRgRMZuJA+PO)pJDqRTqX_H$PuSyI{i?Ei-fxwVrG7$Hs8m&TRaJFp_j;Oa={w;^|*eYMR;9^b*TdtkpmDiY&S0sEf ztzC^`ua+V|Gw+~}&dow9C?(gc1jjH()t%?rP@T9ltevV^vyZ}qE{wyDSd`Di{!BH? z2?jJimoXRs%rIgGC}wyCSjW?lB>|;xtW<%TkP=AVxz{wV{|98{bl@OWYCzMzDim=? zxP`xieVqFKNNcy;ep%lv+yskR7EE9Mya$ZrD`OcDP66*HF;vJ>HqM{L;;t@KHc8D6ioFQNAKbl+?UNt_#US}CvC=`UyW zh@PLME{KK9w0evGR4I2RB(ZLggr;tve9@~UK2HioPwm4%-MPQGzd{K~v>KRnLCYw% zi^HttPwi1w-0k)a>54pcjJVfms5M!%gYH?k6eXRU3iovQG%+`~`q!G&*3{aq_r2J& z(0#HIE$8+_XORWmR~58KKwyp$ky?@#`K}M=W*uIm!)zd1ZG}<1Pds3a{LanINC{;D z*0+^i4)srUt#Z!h_wQsfH>k}2CZ=$9WuJGtTic@hkd;2sy=Nj~j$8O~Kw!ztQ}3}q zX9edf2I;0xaZzD;ma!^zD(KJhZ9NWz%1N)G_9i)LJjOkSlPDZ)rV)Z8zk}I$^h@CG zkR{Cb(xwB@u;IWDt8fxW6AeWryJ6zu4ArE4D znUt4G=|DcaL`?D0mEg`3eyR~(^pO#1T!Q7cn$af*rP)zp3I|uvSI~0BmUwi*BdTf5 z+V2Kmz}JDt7!mO(Yn_z_>1xy+LtF%#xx7}%@5pS>|ITxrb7Pk`S_nKJZ3+-vP*6qB zTeuPMCt=PWQ(u-mjxCL;e7!QmGXU)OhaKDmC_ecY$)D@=F2jI$x zCMk69W+Q)JV`b*2-RNAlJAZ7{nqRpbnQhI|{b+KEq5{Ex6D1#+_rq6B?hbb9M9h+v zhTwnYve~j~_TqG3c`c_DN^6_r8%w;+J@lKa`*q@Nz@X%q2N&+F@GD z>WZvP!BV-2%=as`%somavAS*LOy-y7o_mHPspYuK5TFmp;GVn}prA%ydoIow5{n^F zQv8)suvTj|AnP=lFKMtcoLlDnx~vIoe^8U%QS=KVegiG*uVo-uw58-%swv7Qb#b_H zGHxiyp}Ndc8L_q!UOLvE_6_c1d>12jF;&JQ=e4=?;7?+RtFm3ypap`!476|)=97`M zu`t$#@iyK>P(;n$>UV#^lVl?BONYnC+*1{566@ou@Vx=BH|R$&K4E)-B~=5noa$Ng zojMe6f4rQjBu*WK5yHkBVmt=kZZ(Jv^L3B%cPd{xj;%=;eCDD9V1D|si=6btdViBK z-&(PR)Nr9!#I80T^4~C*4PVo-URYF`1b{*Ylm$-4LEof>od9#0l^*+L>lB+c>@GU>2`zdOeVOG%18RwJ^wGWLZC%(S!d0rTobnr)#sFM-*s_B$ zh!6vP@hfe$2~gkZG>sJF{tCc6qrBMH7OC0$X2K7aMyH zK`KmY;zf*u<;v`N=nE0g zX1XRU^Hfmrt0?GY#hsH4-L5uF!8F~uGE#7-WMIb{47%8R?JWdI-J{(8o?%CH^@gba zHB_etYRRFTsF3l=CZH@QHLh1m**hYD5a;uV?IS~L+D!VUbX>Pim<2aJTz?6BDSaOx;MIi+XN&N1n95phD)EQ&J2>SosX|xQqwrw;F2~j8uZ?LGo)4np;K1y}bb`as%i6E6LiCk7F7|jbwIOQ9RT<$(zN;H}d45+s*$G#$-r zxXSlQuTxle=_t=vVu!$<)YD$=H`{V>%?UiXTr5~Wk3f(La%$DGI}F#b zw3{&yEF-Y=RBatrgRhfqRu?Za#CSMy^Gs&}rW6|Q^qC$M>JcGqj2G8uHH=9xomeV) z&Ug9U+BgAx1^d1%y$imP&)}@oMAGx-7oA8GfzW1rg5AS`($$uG<(d6t6G($=(9=-| z0(}l81D}IIn6G>Dw{>7{X1}X~TGX_`PSLLF=~&hJ!8nr0m~by=2_85(e9-}(IyRBMv zWU$U8hvDWh`q#Myvk!)WGKz@z->cNU5J90z9)5rk7f zZhojD_&9uK&?UN!Ib9?GOlqlm(|UJhFz`lCU=PiwyATXYE3J^ZDN~J_U+gefv-yee zS>rCNzR~Z89-B?pvx7@jiThes8^I7sJIpz`SnCFrXkvEFUVkIIlkaoc)}4f)43c}N zr#InMHci@ptk8d_Zs=}3X>#|j-9(J`t?Y}x39>OWA+BSnz7k_iF{rm~dWn}#ZI<>W z#%TI*NAEOP3428n-@U+E4VHncBgOWz_K^4XX9ox38OwJ@=)MtRT)ul9OFGSH3KFF? zW>)ib^|$6|lIi=2z`wf&>Zzf=?^7qOD4=v&t0W>4rhM$#&8QRu<439?5ZXZ|yPtsN2sR#J0-R^? zvnuB(XVBTNPC&_w(_shINkxrIG38II{8axxGcW1ALFdHDlIHN>>OX}DfU;4>*xWrv zi}m|grXJ}hew>%eV}KqV>V5@T?Oj2SclA3#OoX57xAm^{PKozH?c8Z<^MuI*MAS@e zq)p3y;PWKq^Etj$8OY#wYJS+s9Dky*f9?%=+SWjdI^*%OgW9g~f&$3`$q8|J=~&AB zSHf{)A@3-Y`}VLDdn4wmyvlfmw>5v-)@#&|9tu|6aPE&@F{a2pKcy4MVcDH8PW%eLN`i+9bEMeG{ic4cHJA{2GQQwj-Fu z-)?~?`O~Xw?0H=3mtD~J=uM0Z>-4mH_=Kni^&iQ5$;Ingeg2k`_q!513(XZeA#e_q z^vKAB23yKKZ?uVlZzN`yQbI09=bl!&`f$UG<}UFK8T$#)elfUz%DIdfpfBn-vFQ9x zV&ZPJ&)|p6ns1qXg8rhC2VOxb=cA$spVAGY>6sSfJ2ZoV+f7T$*7ilKA%LzB(m(2@!(Bw)RRbNmR zdn+YPs}ITTLAZZmb3lPlJ zO%4^xc1IJpw2&_qjMrN$@%p2zcGPy;^;tB`COJ8j&|F;F>CG6jUxcEb8x!~tI|my_ zMm)Lg`Nblu!ETp;*-lW!rh@VOUCpHD#-~A^Z27Ve$BZ#E^e&SEdsaZ6RR5Yxg{})9 z&yT6nsRTI5$E#$6hEurjWiF)b@uR6X{5*Kk4uZ|lj|aKIomW7Jzv>fNe!UeZ=eWA=g9;L(Binr8!3Wc*Va4^At;97pI+KB)m~ zc!;~NJcu$W0&ZZ1;BgEYun2ufL#B%`@ACZ-P9JAt5Rt{1a00x?eXzWWHM>2pW>jP` z4b<35|KrCR*?}ugjR?z5k7G}oK8ezD&OLl)zXDauD00CWOn)UEmBMM&)Pm#}p&a|B zI#$AGfE2Y|K2XtAaDS%qP`S5yH;V1`#EvEn?2Y0KivDsg{sKXnynxl6BwE>4yK&kY z94TlrQ5x1*EY)%vRPBx9520doM@orKu$!s)OAbi5ByQbZ)KMfe!$**(170MS`HZMR zeBxT}q#nxgJ#Kk)rpQlNmn|pQ;=e&4T)t+4HZ?HUoBl;8xlSef5bYxR^3|;xkp^G4 zCp@jM{X9qq-X2{v11wDV<&Y_LhD9)c zo+8wJRk9R=^3jywW!qeQAq+atXaO${b%1M4{Nn)hF9WgD`W_CmlD>KdSH&~~Y~u=Z zgLjh|acj`dJ);NA$v~CWAX$RG;=MfP>P-bL_WqSe2b4U^3ny{{XntXkIL*opAc416 z-#d*xUbM|fvPitTEcOQjP45Ba-Ir{?{tcYlG)d;Y>+yYa^jra#Nv37 zX1A+x@iM^S?}SLg(?3Vg&4t!Up;%RXS$(F%0uMBCU~VYM51wv$*#=ZPo>6!tk?PM^Ul<83+@1`^Vt_~ zD|OdkT68YC?_BUK=XgrBv_-E5Eeh6(W)3Q5H7euE@1{af@t$cV=}@y6b{83>tNN!* zC3y~CrvEmH(@zx zGM9{;z%hmtF8}D|gMdRr855Mq=()NDzJdNCz8ziaOpFn4$WCnUC#wBjo)?AeC<3wR zNlR@i9VD1Jov3%kcy11Q>z*!B4v4DiU1gIE&~RjBxGsXMPTRd+$P)r}$Kt|fV#lsL z%8!f>O=o4|WNH?G+Rb^`o1S}HNxe+hdD!l=bAe{?xD@QVOq-9HnbLf*Li7f8r-9N( zh^%l{!Y96Zy^K{#F>iqDv&TY75oB>}VNsmmYW)i!@iK-@ccG|mqwfogZj6I^aH&de*iy|3X1v_#dhPN%CYD75 zvbLnnSCSqZr#Z&yhx+0Od$8hZUfCsnqv=qmqrbE*bH*F@Cin~8w=Mx^#-d^q93$cH zAc+kJuO40J(*p2M_Ack_LrVMfFpUY{S0G?L6EwG(Dr(2$hIjOgCUR$3nR_+&)jHNp*1MA&UBW9I)pc;r$5R`0k{4BZ zswM^EFmrT4kWONacQuzTCPB(w{K_F~JT7R?^K|+{X;ZOa&Y?}q1b-(Lw4dNa7+x6V zKUNCit4WkSn7YV%ya>-Q)z?Yg=@}gDrt8%RW*=G8oKENq3P<3}$0*t5O^x{+S7qZM zJ-Cjjh)chuiy~NAbulbzG{(=;>$d!L4IYAJiYLO!AA87~kB*65j95}R3-HN^jB4`y zO!QV}8_9H=jJqQ%6Lwy}9^V-?YQ>I^voz%AX%?{WA=`9{&Z1lOKhf#gylDgv+k~BeJUc*xOpL!N*K_Zv1?3466Dy z8I{Hu#nvJxbfyT~^Sg08lMrC|DouNa5}9$f^o2zQCHw;9+<$BXs=gh zsHA7Ih+n=RwM@CO?$>i0dRS!M|7*m}t1lT;-WNi?v>ARg^1M3)`oiy!y_>p6`ETze z($}TD;GGXxSWU&Ia+$a_9DP@AqKPF(0rOiY@>@y>F(pKxF~Fm3P#k;xtxGkhlAfJl zL+175s0_A}TC#V(SW)%Yp)>)86DT(-D4853dbU`1&mQYS7 z9H1lYWk9F7xXUAvUP6cienPSbzox~%aXlk_=PZ_L`iGc;`pS6cVtN5co#}wthMsg< zft{6hOYgbDOd7<6O{D7t|A+-}CSUo!ai?4{aY3C2wq2fC`3v>rRm>&G)(8w%tdv!a zMP7~8TYz0Lz=LjP9Zes!H;jK>rx%|ic*bR9U$$KSORy!e-+eXNC)C))2B+rR1F>w# zUP(V$>BU)&GxSs<3)EQ8*|W{w37IgO(Bo`wLA+g9e(Jq96Nj4ekuT+0PsP>}IR7b6 zV+7-he0y}5T^hMWRnNH6eSRxuC_5exl!TNWrAHZHiuY5l-#9xOe>NTA>mr8?-SW>fk;zc!n&1?I7 zKCHM;=5!Q^uVyTwDztx%t(cY;+2+gQ-K%ghX66_-tm8F2rDjk> zE&eqxs=TY1eoSt28-JBWSk+nK=(Ic-i}j^iMlZ#F#+GUPZTPT44pfZ#q+jl@p-#15 zPsL#wj1INVtTlnpP4;@0N>Ad;SH342aEwCu+UbH2O%-6f@x;hFk=dglWc95=dz-PH}X2FL5v zso+P&*_%r}ys$Ty^VL7^c5H*)P05p~QkBA{=iMe}_ZuRH6h9fyV$=8gn&YsFg?)yr z%blJe@d6JG9t31*$-vb`V;855(rS>hort<)U?gq7ZBqvOJ;XRt7*n%P7WcTT{Q4E+ z7`yBWxnQa=AV?4Sl3y{(e3zNB$w2RwQ^#7ImRvz|b(*K$K_OY_Ome+3YZ1y534;uv zRSW%CQKurzkd(ZiMU{T$qY6$2%ITNGBC@Uwkh*XsS(nj8ev}qEmvuG=A((Y_{Q&so z5PaI5d?dGgT*d3FEADJJnIF`qc1g>+_gJ-|LaXVHY%1vZLl!kVz2~M&#{O7tDOc_8 zs7pkiD}RXRg+2to&2^QGz}fCp3we!^!eCVEMbhpvM{lh9F>Pt0ic{gBS}pdyu~Q7s z6_7I7ulN0MC3C&R&efaA^>^9a-B0VYRgL|8^qnzz9}$~hOLU7Exe*? zIj@f`KJ&PCe;nJ{SkQ?ZF1`7@vrhDd@h5hEnEMg*W`plkLS?hK+44cr-q>}+8scp` zDZ^OSKRsnQtbaA259L-`zpiNBr1@3<8kIBHXfWrZ;mYY|dg-#*qb^>qS#JgryikAW zhqPWj2zZ>wIvwjFB^hBgiGKDV@Tj4>b_S;l*?P!8fz%IEHFg(^ zm$JyI;>lfw6{fHu)d)-uWN~y2ZgN#}@6x7iVbWPQMKD(4bXq=aY+@pTk+}0D8(%RI*J~{vZ3keWzBIJX13$QJd7g$ehp{AC~i3 z&N*F|ekkFa4?;}E@+4ii&U3EI(Yi{W#q1wkD34JEy%aLZgR7>lt41iTyqZwZi*$hRI~_R>ox+>?(i5&%|Hm>`3j(&)_rv WubU>a9)CZGQhKiXtn?`~@c#k#=|!0U literal 0 HcmV?d00001 diff --git a/crates/collab_ui/src/collab_titlebar_item.rs b/crates/collab_ui/src/collab_titlebar_item.rs index f9f5738ad26762dd9e4fc5c08c6cf48439b90e67..a16c31595fa116c7128baa618b7c7cf16604c52d 100644 --- a/crates/collab_ui/src/collab_titlebar_item.rs +++ b/crates/collab_ui/src/collab_titlebar_item.rs @@ -823,7 +823,7 @@ impl CollabTitlebarItem { avatar_style: AvatarStyle, background_color: Color, ) -> ElementBox { - Image::new(avatar) + Image::from_data(avatar) .with_style(avatar_style.image) .aligned() .contained() diff --git a/crates/collab_ui/src/contact_finder.rs b/crates/collab_ui/src/contact_finder.rs index 98f70e83f0ecf1eb3c312429a8461a35b028199e..cb55669ab0a29230c2aa06a09ac6cd1718b68221 100644 --- a/crates/collab_ui/src/contact_finder.rs +++ b/crates/collab_ui/src/contact_finder.rs @@ -128,7 +128,7 @@ impl PickerDelegate for ContactFinder { .style_for(mouse_state, selected); Flex::row() .with_children(user.avatar.clone().map(|avatar| { - Image::new(avatar) + Image::from_data(avatar) .with_style(theme.contact_finder.contact_avatar) .aligned() .left() diff --git a/crates/collab_ui/src/contact_list.rs b/crates/collab_ui/src/contact_list.rs index 3bb036d3366a4de8f4bb8e8253ae4470ce86edbc..203d130b5b48d481797390dd3491f3d6e9d28314 100644 --- a/crates/collab_ui/src/contact_list.rs +++ b/crates/collab_ui/src/contact_list.rs @@ -726,7 +726,7 @@ impl ContactList { ) -> ElementBox { Flex::row() .with_children(user.avatar.clone().map(|avatar| { - Image::new(avatar) + Image::from_data(avatar) .with_style(theme.contact_avatar) .aligned() .left() @@ -1080,7 +1080,7 @@ impl ContactList { }; Stack::new() .with_child( - Image::new(avatar) + Image::from_data(avatar) .with_style(theme.contact_avatar) .aligned() .left() @@ -1173,7 +1173,7 @@ impl ContactList { let mut row = Flex::row() .with_children(user.avatar.clone().map(|avatar| { - Image::new(avatar) + Image::from_data(avatar) .with_style(theme.contact_avatar) .aligned() .left() diff --git a/crates/collab_ui/src/incoming_call_notification.rs b/crates/collab_ui/src/incoming_call_notification.rs index a0f54abe386ca56ef416f051dc2474e1736cc332..6fb0278218987d0e50ea7acc8792a24258426702 100644 --- a/crates/collab_ui/src/incoming_call_notification.rs +++ b/crates/collab_ui/src/incoming_call_notification.rs @@ -108,7 +108,7 @@ impl IncomingCallNotification { .unwrap_or(&default_project); Flex::row() .with_children(self.call.calling_user.avatar.clone().map(|avatar| { - Image::new(avatar) + Image::from_data(avatar) .with_style(theme.caller_avatar) .aligned() .boxed() diff --git a/crates/collab_ui/src/notifications.rs b/crates/collab_ui/src/notifications.rs index 06b6cf2a90984fe57b932892f94fda83bb06b369..21c2d2c2185ed69d6c19ad85be51cff1231d5bcb 100644 --- a/crates/collab_ui/src/notifications.rs +++ b/crates/collab_ui/src/notifications.rs @@ -24,7 +24,7 @@ pub fn render_user_notification( .with_child( Flex::row() .with_children(user.avatar.clone().map(|avatar| { - Image::new(avatar) + Image::from_data(avatar) .with_style(theme.header_avatar) .aligned() .constrained() diff --git a/crates/collab_ui/src/project_shared_notification.rs b/crates/collab_ui/src/project_shared_notification.rs index edf0354eec0d53be306e613697962a72cc34a683..b24f3492da933f4a868be65cfb2f3344679fc6c6 100644 --- a/crates/collab_ui/src/project_shared_notification.rs +++ b/crates/collab_ui/src/project_shared_notification.rs @@ -108,7 +108,7 @@ impl ProjectSharedNotification { let theme = &cx.global::().theme.project_shared_notification; Flex::row() .with_children(self.owner.avatar.clone().map(|avatar| { - Image::new(avatar) + Image::from_data(avatar) .with_style(theme.owner_avatar) .aligned() .boxed() diff --git a/crates/gpui/src/assets.rs b/crates/gpui/src/assets.rs index ac0d72dee97a8d5553963c4677bc3f6051fbaf34..2170d215af078257326c258c7502f4c90c84e19e 100644 --- a/crates/gpui/src/assets.rs +++ b/crates/gpui/src/assets.rs @@ -1,5 +1,8 @@ use anyhow::{anyhow, Result}; -use std::{borrow::Cow, cell::RefCell, collections::HashMap}; +use image::ImageFormat; +use std::{borrow::Cow, cell::RefCell, collections::HashMap, sync::Arc}; + +use crate::ImageData; pub trait AssetSource: 'static + Send + Sync { fn load(&self, path: &str) -> Result>; @@ -22,6 +25,7 @@ impl AssetSource for () { pub struct AssetCache { source: Box, svgs: RefCell>, + pngs: RefCell>>, } impl AssetCache { @@ -29,6 +33,7 @@ impl AssetCache { Self { source: Box::new(source), svgs: RefCell::new(HashMap::new()), + pngs: RefCell::new(HashMap::new()), } } @@ -43,4 +48,18 @@ impl AssetCache { Ok(svg) } } + + pub fn png(&self, path: &str) -> Result> { + let mut pngs = self.pngs.borrow_mut(); + if let Some(png) = pngs.get(path) { + Ok(png.clone()) + } else { + let bytes = self.source.load(path)?; + let image = ImageData::new( + image::load_from_memory_with_format(&bytes, ImageFormat::Png)?.into_bgra8(), + ); + pngs.insert(path.to_string(), image.clone()); + Ok(image) + } + } } diff --git a/crates/gpui/src/elements/image.rs b/crates/gpui/src/elements/image.rs index 37cb01ace8a6c43e0add3d366d888f06b4b0225e..cc49308e15011b317840da086170c28d1132996d 100644 --- a/crates/gpui/src/elements/image.rs +++ b/crates/gpui/src/elements/image.rs @@ -11,8 +11,13 @@ use crate::{ use serde::Deserialize; use std::{ops::Range, sync::Arc}; +enum ImageSource { + Path(&'static str), + Data(Arc), +} + pub struct Image { - data: Arc, + source: ImageSource, style: ImageStyle, } @@ -31,9 +36,16 @@ pub struct ImageStyle { } impl Image { - pub fn new(data: Arc) -> Self { + pub fn new(asset_path: &'static str) -> Self { + Self { + source: ImageSource::Path(asset_path), + style: Default::default(), + } + } + + pub fn from_data(data: Arc) -> Self { Self { - data, + source: ImageSource::Data(data), style: Default::default(), } } @@ -45,39 +57,53 @@ impl Image { } impl Element for Image { - type LayoutState = (); + type LayoutState = Option>; type PaintState = (); fn layout( &mut self, constraint: SizeConstraint, - _: &mut LayoutContext, + cx: &mut LayoutContext, ) -> (Vector2F, Self::LayoutState) { + let data = match &self.source { + ImageSource::Path(path) => match cx.asset_cache.png(path) { + Ok(data) => data, + Err(error) => { + log::error!("could not load image: {}", error); + return (Vector2F::zero(), None); + } + }, + ImageSource::Data(data) => data.clone(), + }; + let desired_size = vec2f( self.style.width.unwrap_or_else(|| constraint.max.x()), self.style.height.unwrap_or_else(|| constraint.max.y()), ); let size = constrain_size_preserving_aspect_ratio( constraint.constrain(desired_size), - self.data.size().to_f32(), + data.size().to_f32(), ); - (size, ()) + + (size, Some(data)) } fn paint( &mut self, bounds: RectF, _: RectF, - _: &mut Self::LayoutState, + layout: &mut Self::LayoutState, cx: &mut PaintContext, ) -> Self::PaintState { - cx.scene.push_image(scene::Image { - bounds, - border: self.style.border, - corner_radius: self.style.corner_radius, - grayscale: self.style.grayscale, - data: self.data.clone(), - }); + if let Some(data) = layout { + cx.scene.push_image(scene::Image { + bounds, + border: self.style.border, + corner_radius: self.style.corner_radius, + grayscale: self.style.grayscale, + data: data.clone(), + }); + } } fn rect_for_text_range( diff --git a/crates/project_panel/src/project_panel.rs b/crates/project_panel/src/project_panel.rs index 1cefc558f00d3f5e3c4f3c73987a42f8b4755652..9df6581d209c47b4e3763ca9acf12da1ce378189 100644 --- a/crates/project_panel/src/project_panel.rs +++ b/crates/project_panel/src/project_panel.rs @@ -1325,7 +1325,7 @@ impl View for ProjectPanel { Canvas::new(|bounds, _visible_bounds, cx| { cx.scene.push_quad(gpui::Quad { bounds, - background: Some(Color::red()), + background: Some(Color::transparent_black()), ..Default::default() }) }) diff --git a/crates/welcome/src/welcome.rs b/crates/welcome/src/welcome.rs index 7bf6c263023470ca784f7d4f1e05283a9926cfd3..232fd1bcb732aeda9cdace32a48e303f2dd36e78 100644 --- a/crates/welcome/src/welcome.rs +++ b/crates/welcome/src/welcome.rs @@ -1,14 +1,13 @@ use std::borrow::Cow; use gpui::{ - color::Color, - elements::{Canvas, Empty, Flex, Label, MouseEventHandler, ParentElement, Stack, Svg}, + elements::{Canvas, Empty, Flex, Image, Label, MouseEventHandler, ParentElement, Stack}, geometry::rect::RectF, Action, Element, ElementBox, Entity, MouseButton, MouseRegion, MutableAppContext, RenderContext, Subscription, View, ViewContext, }; use settings::{settings_file::SettingsFile, Settings, SettingsFileContent}; -use theme::{CheckboxStyle, ContainedText, Interactive}; +use theme::CheckboxStyle; use workspace::{item::Item, Welcome, Workspace}; pub fn init(cx: &mut MutableAppContext) { @@ -72,15 +71,14 @@ impl View for WelcomePage { .with_children([ Flex::row() .with_children([ - Svg::new("icons/terminal_16.svg") - .with_color(Color::red()) + Image::new("images/zed-logo-90x90.png") .constrained() - .with_width(100.) - .with_height(100.) + .with_width(90.) + .with_height(90.) .aligned() .contained() .boxed(), - Label::new("Zed", theme.editor.hover_popover.prose.clone()).boxed(), + // Label::new("Zed", theme.editor.hover_popover.prose.clone()).boxed(), ]) .boxed(), Label::new( From 4a8527478df335c27bf1cd601676d82fb73e535f Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Mon, 6 Mar 2023 11:51:58 -0800 Subject: [PATCH 14/93] Add child item alignment to flex implementation Fix checkbox styling co-authored-by: Nathan --- crates/gpui/src/elements/flex.rs | 32 ++++++++++++++++++++++++- crates/theme/src/theme.rs | 2 ++ crates/welcome/src/welcome.rs | 16 +++++++++---- styles/src/styleTree/welcome.ts | 41 +++++++++++++++++++++----------- 4 files changed, 72 insertions(+), 19 deletions(-) diff --git a/crates/gpui/src/elements/flex.rs b/crates/gpui/src/elements/flex.rs index ce595222f3f8a3c2e95019f19f790114f05653fd..b1427269949d050c2972bd1096601c902bdbabce 100644 --- a/crates/gpui/src/elements/flex.rs +++ b/crates/gpui/src/elements/flex.rs @@ -22,6 +22,7 @@ pub struct Flex { axis: Axis, children: Vec, scroll_state: Option<(ElementStateHandle>, usize)>, + child_alignment: f32, } impl Flex { @@ -30,6 +31,7 @@ impl Flex { axis, children: Default::default(), scroll_state: None, + child_alignment: -1., } } @@ -41,6 +43,15 @@ impl Flex { Self::new(Axis::Vertical) } + /// Render children centered relative to the cross-axis of the parent flex. + /// + /// If this is a flex row, children will be centered vertically. If this is a + /// flex column, children will be centered horizontally. + pub fn align_children_center(mut self) -> Self { + self.child_alignment = 0.; + self + } + pub fn scrollable( mut self, element_id: usize, @@ -309,7 +320,26 @@ impl Element for Flex { } } - child.paint(child_origin, visible_bounds, cx); + // We use the child_alignment f32 to determine a point along the cross axis of the + // overall flex element and each child. We then align these points. So 0 would center + // each child relative to the overall height/width of the flex. -1 puts children at + // the start. 1 puts children at the end. + let cross_axis = self.axis.invert(); + let my_center = bounds.size().along(cross_axis) / 2.; + let my_target = my_center + my_center * self.child_alignment; + + let child_center = child.size().along(cross_axis) / 2.; + let child_target = child_center + child_center * self.child_alignment; + + let mut aligned_child_origin = child_origin; + match self.axis { + Axis::Horizontal => aligned_child_origin + .set_y(aligned_child_origin.y() - (child_target - my_target)), + Axis::Vertical => aligned_child_origin + .set_x(aligned_child_origin.x() - (child_target - my_target)), + } + + child.paint(aligned_child_origin, visible_bounds, cx); match self.axis { Axis::Horizontal => child_origin += vec2f(child.size().x(), 0.0), diff --git a/crates/theme/src/theme.rs b/crates/theme/src/theme.rs index ded5c54f832ba53cbcc9c4ab998ed38122b38631..9442f08d24704af9d4f2309aeadd512cb114e3f5 100644 --- a/crates/theme/src/theme.rs +++ b/crates/theme/src/theme.rs @@ -859,6 +859,8 @@ pub struct WelcomeStyle { #[derive(Clone, Deserialize, Default)] pub struct CheckboxStyle { + pub icon: String, + pub icon_color: Color, pub width: f32, pub height: f32, pub default: ContainerStyle, diff --git a/crates/welcome/src/welcome.rs b/crates/welcome/src/welcome.rs index 232fd1bcb732aeda9cdace32a48e303f2dd36e78..f787a6cf24b038f370a6344c031f78b4d8e9664d 100644 --- a/crates/welcome/src/welcome.rs +++ b/crates/welcome/src/welcome.rs @@ -1,7 +1,7 @@ use std::borrow::Cow; use gpui::{ - elements::{Canvas, Empty, Flex, Image, Label, MouseEventHandler, ParentElement, Stack}, + elements::{Canvas, Empty, Flex, Image, Label, MouseEventHandler, ParentElement, Stack, Svg}, geometry::rect::RectF, Action, Element, ElementBox, Entity, MouseButton, MouseRegion, MutableAppContext, RenderContext, Subscription, View, ViewContext, @@ -104,6 +104,7 @@ impl View for WelcomePage { ) .boxed(), ]) + .align_children_center() .boxed(), Flex::row() .with_children([ @@ -119,9 +120,9 @@ impl View for WelcomePage { ) .boxed(), ]) + .align_children_center() .boxed(), ]) - .aligned() .boxed(), ) .boxed() @@ -177,8 +178,15 @@ impl WelcomePage { set_value: fn(&mut SettingsFileContent, checked: bool) -> (), ) -> ElementBox { MouseEventHandler::::new(0, cx, |state, _| { - Empty::new() - .constrained() + let indicator = if checked { + Svg::new(style.icon.clone()) + .with_color(style.icon_color) + .constrained() + } else { + Empty::new().constrained() + }; + + indicator .with_width(style.width) .with_height(style.height) .contained() diff --git a/styles/src/styleTree/welcome.ts b/styles/src/styleTree/welcome.ts index 114ff0b7df69e12a0229698c3232c995e1edde2f..02e3c11f914f1b15b8cdd190589147f242217b70 100644 --- a/styles/src/styleTree/welcome.ts +++ b/styles/src/styleTree/welcome.ts @@ -1,6 +1,6 @@ import { ColorScheme } from "../themes/common/colorScheme"; -import { border, background, text } from "./components"; +import { border, background, foreground, text } from "./components"; export default function welcome(colorScheme: ColorScheme) { @@ -10,15 +10,18 @@ export default function welcome(colorScheme: ColorScheme) { let checkboxBase = { cornerRadius: 4, padding: { - left: 8, - right: 8, - top: 4, - bottom: 4, + left: 3, + right: 3, + top: 3, + bottom: 3, }, shadow: colorScheme.popoverShadow, border: border(layer), margin: { - left: -8, + left: 8, + right: 8, + top: 5, + bottom: 5 }, }; @@ -44,30 +47,40 @@ export default function welcome(colorScheme: ColorScheme) { }, }, checkbox: { - width: 9, - height: 9, + width: 12, + height: 12, + icon: "icons/check_12.svg", + iconColor: foreground(layer, "on"), default: { ...checkboxBase, - background: colorScheme.ramps.blue(0.5).hex(), + background: background(layer, "default"), + border: { + color: foreground(layer, "hovered"), + width: 1, + } }, checked: { ...checkboxBase, - background: colorScheme.ramps.red(0.5).hex(), + background: background(layer, "hovered"), + border: { + color: foreground(layer, "hovered"), + width: 1, + } }, hovered: { ...checkboxBase, - background: colorScheme.ramps.blue(0.5).hex(), + background: background(layer, "hovered"), border: { - color: colorScheme.ramps.green(0.5).hex(), + color: foreground(layer, "hovered"), width: 1, } }, hoveredAndChecked: { ...checkboxBase, - background: colorScheme.ramps.red(0.5).hex(), + background: background(layer, "hovered"), border: { - color: colorScheme.ramps.green(0.5).hex(), + color: foreground(layer, "hovered"), width: 1, } } From b74553455f7712e2cf3e9fc738fdc0dc882685ef Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Mon, 6 Mar 2023 14:14:36 -0800 Subject: [PATCH 15/93] Add an element to pane to take care of wiring initial mouse handlers --- crates/gpui/src/elements/flex.rs | 30 +++--- crates/welcome/src/welcome.rs | 154 ++++++++++++++----------------- crates/workspace/src/pane.rs | 91 +++++++++++++++++- 3 files changed, 175 insertions(+), 100 deletions(-) diff --git a/crates/gpui/src/elements/flex.rs b/crates/gpui/src/elements/flex.rs index b1427269949d050c2972bd1096601c902bdbabce..5df283bfee2f20a7b51ec1900526764eab3ef0d4 100644 --- a/crates/gpui/src/elements/flex.rs +++ b/crates/gpui/src/elements/flex.rs @@ -324,20 +324,24 @@ impl Element for Flex { // overall flex element and each child. We then align these points. So 0 would center // each child relative to the overall height/width of the flex. -1 puts children at // the start. 1 puts children at the end. - let cross_axis = self.axis.invert(); - let my_center = bounds.size().along(cross_axis) / 2.; - let my_target = my_center + my_center * self.child_alignment; - - let child_center = child.size().along(cross_axis) / 2.; - let child_target = child_center + child_center * self.child_alignment; + let aligned_child_origin = { + let cross_axis = self.axis.invert(); + let my_center = bounds.size().along(cross_axis) / 2.; + let my_target = my_center + my_center * self.child_alignment; + + let child_center = child.size().along(cross_axis) / 2.; + let child_target = child_center + child_center * self.child_alignment; + + let mut aligned_child_origin = child_origin; + match self.axis { + Axis::Horizontal => aligned_child_origin + .set_y(aligned_child_origin.y() - (child_target - my_target)), + Axis::Vertical => aligned_child_origin + .set_x(aligned_child_origin.x() - (child_target - my_target)), + } - let mut aligned_child_origin = child_origin; - match self.axis { - Axis::Horizontal => aligned_child_origin - .set_y(aligned_child_origin.y() - (child_target - my_target)), - Axis::Vertical => aligned_child_origin - .set_x(aligned_child_origin.x() - (child_target - my_target)), - } + aligned_child_origin + }; child.paint(aligned_child_origin, visible_bounds, cx); diff --git a/crates/welcome/src/welcome.rs b/crates/welcome/src/welcome.rs index f787a6cf24b038f370a6344c031f78b4d8e9664d..f1d59ce7a148010582998363140975cef86f028d 100644 --- a/crates/welcome/src/welcome.rs +++ b/crates/welcome/src/welcome.rs @@ -1,14 +1,13 @@ use std::borrow::Cow; use gpui::{ - elements::{Canvas, Empty, Flex, Image, Label, MouseEventHandler, ParentElement, Stack, Svg}, - geometry::rect::RectF, - Action, Element, ElementBox, Entity, MouseButton, MouseRegion, MutableAppContext, - RenderContext, Subscription, View, ViewContext, + elements::{Empty, Flex, Image, Label, MouseEventHandler, ParentElement, Svg}, + Action, Element, ElementBox, Entity, MouseButton, MutableAppContext, RenderContext, + Subscription, View, ViewContext, }; use settings::{settings_file::SettingsFile, Settings, SettingsFileContent}; use theme::CheckboxStyle; -use workspace::{item::Item, Welcome, Workspace}; +use workspace::{item::Item, PaneBackdrop, Welcome, Workspace, WorkspaceId}; pub fn init(cx: &mut MutableAppContext) { cx.add_action(|workspace: &mut Workspace, _: &Welcome, cx| { @@ -43,89 +42,67 @@ impl View for WelcomePage { enum Metrics {} enum Diagnostics {} - let background = theme.editor.background; - - Stack::new() - .with_child( - // TODO: Can this be moved into the pane? - Canvas::new(move |bounds, visible_bounds, cx| { - let visible_bounds = bounds.intersection(visible_bounds).unwrap_or_default(); - - cx.paint_layer(Some(visible_bounds), |cx| { - cx.scene.push_quad(gpui::Quad { - bounds: RectF::new(bounds.origin(), bounds.size()), - background: Some(background), - ..Default::default() - }) - }); - - cx.scene.push_mouse_region( - MouseRegion::new::(self_handle.id(), 0, visible_bounds) - .on_down(gpui::MouseButton::Left, |_, cx| cx.focus_parent_view()), - ); - }) - .boxed(), - ) - .with_child( - Flex::column() - .with_children([ - Flex::row() - .with_children([ - Image::new("images/zed-logo-90x90.png") - .constrained() - .with_width(90.) - .with_height(90.) - .aligned() - .contained() - .boxed(), - // Label::new("Zed", theme.editor.hover_popover.prose.clone()).boxed(), - ]) - .boxed(), - Label::new( - "Code at the speed of thought", - theme.editor.hover_popover.prose.clone(), - ) - .boxed(), - self.render_cta_button(2, "Choose a theme", theme_selector::Toggle, cx), - self.render_cta_button(3, "Choose a keymap", theme_selector::Toggle, cx), - Flex::row() - .with_children([ - self.render_settings_checkbox::( - &theme.welcome.checkbox, - metrics, - cx, - |content, checked| { - content.telemetry.set_metrics(checked); - }, - ), - Label::new( - "Do you want to send telemetry?", - theme.editor.hover_popover.prose.clone(), - ) + PaneBackdrop::new( + self_handle.id(), + Flex::column() + .with_children([ + Flex::row() + .with_children([ + Image::new("images/zed-logo-90x90.png") + .constrained() + .with_width(90.) + .with_height(90.) + .aligned() + .contained() .boxed(), - ]) - .align_children_center() + // Label::new("Zed", theme.editor.hover_popover.prose.clone()).boxed(), + ]) + .boxed(), + Label::new( + "Code at the speed of thought", + theme.editor.hover_popover.prose.clone(), + ) + .boxed(), + self.render_cta_button(2, "Choose a theme", theme_selector::Toggle, cx), + self.render_cta_button(3, "Choose a keymap", theme_selector::Toggle, cx), + Flex::row() + .with_children([ + self.render_settings_checkbox::( + &theme.welcome.checkbox, + metrics, + cx, + |content, checked| { + content.telemetry.set_metrics(checked); + }, + ), + Label::new( + "Do you want to send telemetry?", + theme.editor.hover_popover.prose.clone(), + ) .boxed(), - Flex::row() - .with_children([ - self.render_settings_checkbox::( - &theme.welcome.checkbox, - diagnostics, - cx, - |content, checked| content.telemetry.set_diagnostics(checked), - ), - Label::new( - "Send crash reports", - theme.editor.hover_popover.prose.clone(), - ) - .boxed(), - ]) - .align_children_center() + ]) + .align_children_center() + .boxed(), + Flex::row() + .with_children([ + self.render_settings_checkbox::( + &theme.welcome.checkbox, + diagnostics, + cx, + |content, checked| content.telemetry.set_diagnostics(checked), + ), + Label::new( + "Send crash reports", + theme.editor.hover_popover.prose.clone(), + ) .boxed(), - ]) - .boxed(), - ) - .boxed() + ]) + .align_children_center() + .boxed(), + ]) + .boxed(), + ) + .boxed() } } @@ -232,4 +209,11 @@ impl Item for WelcomePage { fn show_toolbar(&self) -> bool { false } + fn clone_on_split( + &self, + _workspace_id: WorkspaceId, + cx: &mut ViewContext, + ) -> Option { + Some(WelcomePage::new(cx)) + } } diff --git a/crates/workspace/src/pane.rs b/crates/workspace/src/pane.rs index 235df0202d6fc3fc6f4546596385fee28b0647bf..fe339969617c2214606a9a1dbb6937737ca495c9 100644 --- a/crates/workspace/src/pane.rs +++ b/crates/workspace/src/pane.rs @@ -24,8 +24,8 @@ use gpui::{ keymap_matcher::KeymapContext, platform::{CursorStyle, NavigationDirection}, Action, AnyViewHandle, AnyWeakViewHandle, AppContext, AsyncAppContext, Entity, EventContext, - ModelHandle, MouseButton, MutableAppContext, PromptLevel, Quad, RenderContext, Task, View, - ViewContext, ViewHandle, WeakViewHandle, + ModelHandle, MouseButton, MouseRegion, MutableAppContext, PromptLevel, Quad, RenderContext, + Task, View, ViewContext, ViewHandle, WeakViewHandle, }; use project::{Project, ProjectEntryId, ProjectPath}; use serde::Deserialize; @@ -1706,6 +1706,93 @@ impl NavHistory { } } +pub struct PaneBackdrop { + child_view: usize, + child: ElementBox, +} +impl PaneBackdrop { + pub fn new(pane_item_view: usize, child: ElementBox) -> Self { + PaneBackdrop { + child, + child_view: pane_item_view, + } + } +} + +impl Element for PaneBackdrop { + type LayoutState = (); + + type PaintState = (); + + fn layout( + &mut self, + constraint: gpui::SizeConstraint, + cx: &mut gpui::LayoutContext, + ) -> (Vector2F, Self::LayoutState) { + let size = self.child.layout(constraint, cx); + (size, ()) + } + + fn paint( + &mut self, + bounds: RectF, + visible_bounds: RectF, + _: &mut Self::LayoutState, + cx: &mut gpui::PaintContext, + ) -> Self::PaintState { + let background = cx.global::().theme.editor.background; + + let visible_bounds = bounds.intersection(visible_bounds).unwrap_or_default(); + + cx.scene.push_quad(gpui::Quad { + bounds: RectF::new(bounds.origin(), bounds.size()), + background: Some(background), + ..Default::default() + }); + + let child_view_id = self.child_view; + cx.scene.push_mouse_region( + MouseRegion::new::(child_view_id, 0, visible_bounds).on_down( + gpui::MouseButton::Left, + move |_, cx| { + let window_id = cx.window_id; + cx.focus(window_id, Some(child_view_id)) + }, + ), + ); + + cx.paint_layer(Some(bounds), |cx| { + self.child.paint(bounds.origin(), visible_bounds, cx) + }) + } + + fn rect_for_text_range( + &self, + range_utf16: std::ops::Range, + _bounds: RectF, + _visible_bounds: RectF, + _layout: &Self::LayoutState, + _paint: &Self::PaintState, + cx: &gpui::MeasurementContext, + ) -> Option { + self.child.rect_for_text_range(range_utf16, cx) + } + + fn debug( + &self, + _bounds: RectF, + _layout: &Self::LayoutState, + _paint: &Self::PaintState, + cx: &gpui::DebugContext, + ) -> serde_json::Value { + gpui::json::json!({ + "type": "Pane Back Drop", + "view": self.child_view, + "child": self.child.debug(cx), + }) + } +} + #[cfg(test)] mod tests { use std::sync::Arc; From 020a0965b0cd0a1d8dcf5c89ee61a9f44320afa3 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Mon, 6 Mar 2023 14:16:55 -0800 Subject: [PATCH 16/93] WIP --- crates/welcome/src/welcome.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/crates/welcome/src/welcome.rs b/crates/welcome/src/welcome.rs index f1d59ce7a148010582998363140975cef86f028d..dcc72357edcd158e68729311f0ca7e3947bcf546 100644 --- a/crates/welcome/src/welcome.rs +++ b/crates/welcome/src/welcome.rs @@ -100,6 +100,9 @@ impl View for WelcomePage { .align_children_center() .boxed(), ]) + .aligned() + .constrained() + .with_max_width(300.) .boxed(), ) .boxed() From ba652fc0331cf1c4cc6c161133647ffa533e5d46 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Mon, 6 Mar 2023 16:28:23 -0800 Subject: [PATCH 17/93] Finish basic welcome experience --- crates/theme/src/theme.rs | 8 +- crates/welcome/src/welcome.rs | 135 +++++++++++++-------------- styles/src/styleTree/components.ts | 2 +- styles/src/styleTree/hoverPopover.ts | 78 ++++++++-------- styles/src/styleTree/welcome.ts | 59 ++++++------ 5 files changed, 143 insertions(+), 139 deletions(-) diff --git a/crates/theme/src/theme.rs b/crates/theme/src/theme.rs index 9442f08d24704af9d4f2309aeadd512cb114e3f5..43a10978d6fd1a36e03d59b5dda4523e13d30d10 100644 --- a/crates/theme/src/theme.rs +++ b/crates/theme/src/theme.rs @@ -853,14 +853,18 @@ pub struct FeedbackStyle { #[derive(Clone, Deserialize, Default)] pub struct WelcomeStyle { + pub page_width: f32, + pub logo_subheading: ContainedText, pub checkbox: CheckboxStyle, pub button: Interactive, } #[derive(Clone, Deserialize, Default)] pub struct CheckboxStyle { - pub icon: String, - pub icon_color: Color, + pub check_icon: String, + pub check_icon_color: Color, + pub label: ContainedText, + pub container: ContainerStyle, pub width: f32, pub height: f32, pub default: ContainerStyle, diff --git a/crates/welcome/src/welcome.rs b/crates/welcome/src/welcome.rs index dcc72357edcd158e68729311f0ca7e3947bcf546..c24e0b5b24ccd1cf61f5bf24c26969ba0bd040a2 100644 --- a/crates/welcome/src/welcome.rs +++ b/crates/welcome/src/welcome.rs @@ -34,6 +34,8 @@ impl View for WelcomePage { let settings = cx.global::(); let theme = settings.theme.clone(); + let width = theme.welcome.page_width; + let (diagnostics, metrics) = { let telemetry = settings.telemetry(); (telemetry.diagnostics(), telemetry.metrics()) @@ -46,63 +48,42 @@ impl View for WelcomePage { self_handle.id(), Flex::column() .with_children([ - Flex::row() - .with_children([ - Image::new("images/zed-logo-90x90.png") - .constrained() - .with_width(90.) - .with_height(90.) - .aligned() - .contained() - .boxed(), - // Label::new("Zed", theme.editor.hover_popover.prose.clone()).boxed(), - ]) + Image::new("images/zed-logo-90x90.png") + .constrained() + .with_width(90.) + .with_height(90.) + .aligned() + .contained() + .aligned() .boxed(), Label::new( "Code at the speed of thought", - theme.editor.hover_popover.prose.clone(), + theme.welcome.logo_subheading.text.clone(), ) + .aligned() + .contained() + .with_style(theme.welcome.logo_subheading.container) .boxed(), - self.render_cta_button(2, "Choose a theme", theme_selector::Toggle, cx), - self.render_cta_button(3, "Choose a keymap", theme_selector::Toggle, cx), - Flex::row() - .with_children([ - self.render_settings_checkbox::( - &theme.welcome.checkbox, - metrics, - cx, - |content, checked| { - content.telemetry.set_metrics(checked); - }, - ), - Label::new( - "Do you want to send telemetry?", - theme.editor.hover_popover.prose.clone(), - ) - .boxed(), - ]) - .align_children_center() - .boxed(), - Flex::row() - .with_children([ - self.render_settings_checkbox::( - &theme.welcome.checkbox, - diagnostics, - cx, - |content, checked| content.telemetry.set_diagnostics(checked), - ), - Label::new( - "Send crash reports", - theme.editor.hover_popover.prose.clone(), - ) - .boxed(), - ]) - .align_children_center() - .boxed(), + self.render_cta_button(2, "Choose a theme", theme_selector::Toggle, width, cx), + self.render_cta_button(3, "Choose a keymap", theme_selector::Toggle, width, cx), + self.render_settings_checkbox::( + "Do you want to send telemetry?", + &theme.welcome.checkbox, + metrics, + cx, + |content, checked| content.telemetry.set_metrics(checked), + ), + self.render_settings_checkbox::( + "Send crash reports", + &theme.welcome.checkbox, + diagnostics, + cx, + |content, checked| content.telemetry.set_diagnostics(checked), + ), ]) - .aligned() .constrained() - .with_max_width(300.) + .with_max_width(width) + .aligned() .boxed(), ) .boxed() @@ -129,6 +110,7 @@ impl WelcomePage { region_id: usize, label: L, action: A, + width: f32, cx: &mut RenderContext, ) -> ElementBox where @@ -139,19 +121,23 @@ impl WelcomePage { MouseEventHandler::::new(region_id, cx, |state, _| { let style = theme.welcome.button.style_for(state, false); Label::new(label, style.text.clone()) + .aligned() .contained() .with_style(style.container) + .constrained() + .with_width(width) .boxed() }) .on_click(MouseButton::Left, move |_, cx| { cx.dispatch_action(action.clone()) }) - .aligned() + .with_cursor_style(gpui::CursorStyle::PointingHand) .boxed() } fn render_settings_checkbox( &self, + label: &'static str, style: &CheckboxStyle, checked: bool, cx: &mut RenderContext, @@ -159,35 +145,44 @@ impl WelcomePage { ) -> ElementBox { MouseEventHandler::::new(0, cx, |state, _| { let indicator = if checked { - Svg::new(style.icon.clone()) - .with_color(style.icon_color) + Svg::new(style.check_icon.clone()) + .with_color(style.check_icon_color) .constrained() } else { Empty::new().constrained() }; - indicator - .with_width(style.width) - .with_height(style.height) - .contained() - .with_style(if checked { - if state.hovered() { - style.hovered_and_checked - } else { - style.checked - } - } else { - if state.hovered() { - style.hovered - } else { - style.default - } - }) + Flex::row() + .with_children([ + indicator + .with_width(style.width) + .with_height(style.height) + .contained() + .with_style(if checked { + if state.hovered() { + style.hovered_and_checked + } else { + style.checked + } + } else { + if state.hovered() { + style.hovered + } else { + style.default + } + }) + .boxed(), + Label::new(label, style.label.text.clone()).contained().with_style(style.label.container).boxed(), + ]) + .align_children_center() .boxed() }) .on_click(gpui::MouseButton::Left, move |_, cx| { SettingsFile::update(cx, move |content| set_value(content, !checked)) }) + .with_cursor_style(gpui::CursorStyle::PointingHand) + .contained() + .with_style(style.container) .boxed() } } diff --git a/styles/src/styleTree/components.ts b/styles/src/styleTree/components.ts index edbced8323c390499388071f498ddfa912fc0aed..3f69df981e8124a343c3b534aced6261b72bf309 100644 --- a/styles/src/styleTree/components.ts +++ b/styles/src/styleTree/components.ts @@ -93,7 +93,7 @@ interface Text { underline?: boolean } -interface TextProperties { +export interface TextProperties { size?: keyof typeof fontSizes weight?: FontWeight underline?: boolean diff --git a/styles/src/styleTree/hoverPopover.ts b/styles/src/styleTree/hoverPopover.ts index 032c53112b27f9f6f47f378a23ef59a9ea40ac53..a2a4467d7c5a9a08bc5cd589d4e9d129c7d8aa07 100644 --- a/styles/src/styleTree/hoverPopover.ts +++ b/styles/src/styleTree/hoverPopover.ts @@ -2,44 +2,44 @@ import { ColorScheme } from "../themes/common/colorScheme" import { background, border, text } from "./components" export default function HoverPopover(colorScheme: ColorScheme) { - let layer = colorScheme.middle - let baseContainer = { - background: background(layer), - cornerRadius: 8, - padding: { - left: 8, - right: 8, - top: 4, - bottom: 4, - }, - shadow: colorScheme.popoverShadow, - border: border(layer), - margin: { - left: -8, - }, - } + let layer = colorScheme.middle + let baseContainer = { + background: background(layer), + cornerRadius: 8, + padding: { + left: 8, + right: 8, + top: 4, + bottom: 4, + }, + shadow: colorScheme.popoverShadow, + border: border(layer), + margin: { + left: -8, + }, + } - return { - container: baseContainer, - infoContainer: { - ...baseContainer, - background: background(layer, "accent"), - border: border(layer, "accent"), - }, - warningContainer: { - ...baseContainer, - background: background(layer, "warning"), - border: border(layer, "warning"), - }, - errorContainer: { - ...baseContainer, - background: background(layer, "negative"), - border: border(layer, "negative"), - }, - block_style: { - padding: { top: 4 }, - }, - prose: text(layer, "sans", { size: "sm" }), - highlight: colorScheme.ramps.neutral(0.5).alpha(0.2).hex(), // TODO: blend was used here. Replace with something better - } + return { + container: baseContainer, + infoContainer: { + ...baseContainer, + background: background(layer, "accent"), + border: border(layer, "accent"), + }, + warningContainer: { + ...baseContainer, + background: background(layer, "warning"), + border: border(layer, "warning"), + }, + errorContainer: { + ...baseContainer, + background: background(layer, "negative"), + border: border(layer, "negative"), + }, + block_style: { + padding: { top: 4 }, + }, + prose: text(layer, "sans", { size: "sm" }), + highlight: colorScheme.ramps.neutral(0.5).alpha(0.2).hex(), // TODO: blend was used here. Replace with something better + } } diff --git a/styles/src/styleTree/welcome.ts b/styles/src/styleTree/welcome.ts index 02e3c11f914f1b15b8cdd190589147f242217b70..bfd67cec8d19d29d651e71acfc573f9aa4757c1c 100644 --- a/styles/src/styleTree/welcome.ts +++ b/styles/src/styleTree/welcome.ts @@ -1,12 +1,11 @@ import { ColorScheme } from "../themes/common/colorScheme"; -import { border, background, foreground, text } from "./components"; +import { border, background, foreground, text, TextProperties } from "./components"; export default function welcome(colorScheme: ColorScheme) { let layer = colorScheme.highest; - // TODO let checkboxBase = { cornerRadius: 4, padding: { @@ -18,20 +17,30 @@ export default function welcome(colorScheme: ColorScheme) { shadow: colorScheme.popoverShadow, border: border(layer), margin: { - left: 8, right: 8, top: 5, bottom: 5 }, }; + + let interactive_text_size: TextProperties = { size: "md" } return { + pageWidth: 450, + logoSubheading: { + ...text(layer, "sans", { size: "lg" }), + margin: { + top: 10, + bottom: 7, + }, + }, button: { background: background(layer), - border: border(layer), - cornerRadius: 6, + border: border(layer, "active"), + cornerRadius: 4, margin: { - top: 1, + top: 8, + bottom: 7 }, padding: { top: 1, @@ -39,50 +48,46 @@ export default function welcome(colorScheme: ColorScheme) { left: 7, right: 7, }, - ...text(layer, "sans", "variant", { size: "xs" }), + ...text(layer, "sans", "hovered", interactive_text_size), hover: { - ...text(layer, "sans", "hovered", { size: "xs" }), + ...text(layer, "sans", "hovered", interactive_text_size), background: background(layer, "hovered"), border: border(layer, "hovered"), }, }, checkbox: { + label: { + ...text(layer, "sans", interactive_text_size), + // Also supports margin, container, border, etc. + }, + container: { + margin: { + top: 5, + }, + }, width: 12, height: 12, - icon: "icons/check_12.svg", - iconColor: foreground(layer, "on"), + checkIcon: "icons/check_12.svg", + checkIconColor: foreground(layer, "on"), default: { ...checkboxBase, background: background(layer, "default"), - border: { - color: foreground(layer, "hovered"), - width: 1, - } + border: border(layer, "active") }, checked: { ...checkboxBase, background: background(layer, "hovered"), - border: { - color: foreground(layer, "hovered"), - width: 1, - } + border: border(layer, "active") }, hovered: { ...checkboxBase, background: background(layer, "hovered"), - - border: { - color: foreground(layer, "hovered"), - width: 1, - } + border: border(layer, "hovered") }, hoveredAndChecked: { ...checkboxBase, background: background(layer, "hovered"), - border: { - color: foreground(layer, "hovered"), - width: 1, - } + border: border(layer, "active") } } } From 1f6bd0ea775875d64393093b112140f3c2eedb19 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Mon, 6 Mar 2023 16:35:15 -0800 Subject: [PATCH 18/93] Fix edge case where the welcome page might open in the dock if the user's actions race the welcome experience action --- crates/workspace/src/workspace.rs | 17 +++++++++++++++++ crates/zed/src/zed.rs | 2 +- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index 442d28579fc1be8358cf322fa3f0c264d9cbdec3..cd2cd6fccb3ffd1f5f7cfcab2ae8af76386d9c1a 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -1349,6 +1349,23 @@ impl Workspace { pane } + pub fn add_item_to_center( + &mut self, + item: Box, + cx: &mut ViewContext, + ) -> bool { + if let Some(center_pane) = self.last_active_center_pane.clone() { + if let Some(center_pane) = center_pane.upgrade(cx) { + Pane::add_item(self, ¢er_pane, item, true, true, None, cx); + true + } else { + false + } + } else { + false + } + } + pub fn add_item(&mut self, item: Box, cx: &mut ViewContext) { let active_pane = self.active_pane().clone(); Pane::add_item(self, &active_pane, item, true, true, None, cx); diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index 5d13d41bba066ca041b9f5ffdc76a4a193cd19ba..a9032a264ba8e8fbfc9e3f505ae313038b8e7053 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -266,7 +266,7 @@ pub fn init(app_state: &Arc, cx: &mut gpui::MutableAppContext) { open_new(&app_state, cx, |workspace, cx| { workspace.toggle_sidebar(SidebarSide::Left, cx); let welcome_page = cx.add_view(|cx| welcome::WelcomePage::new(cx)); - workspace.add_item(Box::new(welcome_page.clone()), cx); + workspace.add_item_to_center(Box::new(welcome_page.clone()), cx); Dock::move_dock(workspace, settings::DockAnchor::Bottom, false, cx); cx.focus(welcome_page); cx.notify(); From 8db7e17ac51266c60fdb610ecad4efc81627210f Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Mon, 6 Mar 2023 17:55:58 -0800 Subject: [PATCH 19/93] Move install_cli function to a seperate crate Add install cli button to welcome experience Add toast pop ups for CLI installation status --- Cargo.lock | 14 +++++++ Cargo.toml | 1 + crates/install_cli/Cargo.toml | 18 +++++++++ crates/install_cli/src/install_cli.rs | 56 ++++++++++++++++++++++++++ crates/welcome/Cargo.toml | 1 + crates/welcome/src/welcome.rs | 1 + crates/workspace/Cargo.toml | 1 + crates/workspace/src/notifications.rs | 28 +++++++++---- crates/workspace/src/workspace.rs | 26 +++++++++++- crates/zed/Cargo.toml | 1 + crates/zed/src/menus.rs | 2 +- crates/zed/src/zed.rs | 57 ++------------------------- 12 files changed, 142 insertions(+), 64 deletions(-) create mode 100644 crates/install_cli/Cargo.toml create mode 100644 crates/install_cli/src/install_cli.rs diff --git a/Cargo.lock b/Cargo.lock index c25656bfa9300a42a5a752b2e47bf4abda7f3348..2b894eff353636540473d147ecd6a864cd6d1db1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3018,6 +3018,17 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adab1eaa3408fb7f0c777a73e7465fd5656136fc93b670eb6df3c88c2c1344e3" +[[package]] +name = "install_cli" +version = "0.1.0" +dependencies = [ + "anyhow", + "gpui", + "log", + "smol", + "util", +] + [[package]] name = "instant" version = "0.1.12" @@ -8020,6 +8031,7 @@ dependencies = [ "anyhow", "editor", "gpui", + "install_cli", "log", "project", "settings", @@ -8304,6 +8316,7 @@ dependencies = [ "futures 0.3.25", "gpui", "indoc", + "install_cli", "language", "lazy_static", "log", @@ -8412,6 +8425,7 @@ dependencies = [ "ignore", "image", "indexmap", + "install_cli", "isahc", "journal", "language", diff --git a/Cargo.toml b/Cargo.toml index feb80633c4f48b63562f5adda2a22cd0062e94c8..83618951465273a39ee59ba214d10ddf5628a382 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,6 +26,7 @@ members = [ "crates/go_to_line", "crates/gpui", "crates/gpui_macros", + "crates/install_cli", "crates/journal", "crates/language", "crates/live_kit_client", diff --git a/crates/install_cli/Cargo.toml b/crates/install_cli/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..bbbe9899209733f8abee8500139b56f10389c4a7 --- /dev/null +++ b/crates/install_cli/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "install_cli" +version = "0.1.0" +edition = "2021" +publish = false + +[lib] +path = "src/install_cli.rs" + +[features] +test-support = [] + +[dependencies] +smol = "1.2.5" +anyhow = "1.0.38" +log = "0.4" +gpui = { path = "../gpui" } +util = { path = "../util" } diff --git a/crates/install_cli/src/install_cli.rs b/crates/install_cli/src/install_cli.rs new file mode 100644 index 0000000000000000000000000000000000000000..06561a28f8b6e04c13ef65f1400cbfef858d4db8 --- /dev/null +++ b/crates/install_cli/src/install_cli.rs @@ -0,0 +1,56 @@ +use std::path::Path; + +use anyhow::{Result, anyhow}; +use gpui::{AsyncAppContext, actions}; +use util::ResultExt; + +actions!(cli, [ Install ]); + + +pub async fn install_cli(cx: &AsyncAppContext) -> Result<()> { + let cli_path = cx.platform().path_for_auxiliary_executable("cli")?; + let link_path = Path::new("/usr/local/bin/zed"); + let bin_dir_path = link_path.parent().unwrap(); + + // Don't re-create symlink if it points to the same CLI binary. + if smol::fs::read_link(link_path).await.ok().as_ref() == Some(&cli_path) { + return Ok(()); + } + + // If the symlink is not there or is outdated, first try replacing it + // without escalating. + smol::fs::remove_file(link_path).await.log_err(); + if smol::fs::unix::symlink(&cli_path, link_path) + .await + .log_err() + .is_some() + { + return Ok(()); + } + + // The symlink could not be created, so use osascript with admin privileges + // to create it. + let status = smol::process::Command::new("osascript") + .args([ + "-e", + &format!( + "do shell script \" \ + mkdir -p \'{}\' && \ + ln -sf \'{}\' \'{}\' \ + \" with administrator privileges", + bin_dir_path.to_string_lossy(), + cli_path.to_string_lossy(), + link_path.to_string_lossy(), + ), + ]) + .stdout(smol::process::Stdio::inherit()) + .stderr(smol::process::Stdio::inherit()) + .output() + .await? + .status; + if status.success() { + Ok(()) + } else { + Err(anyhow!("error running osascript")) + } +} \ No newline at end of file diff --git a/crates/welcome/Cargo.toml b/crates/welcome/Cargo.toml index e1231ad5f631a11dfdad9bd77341b14207b572b5..e76636411bba5188084d7c585419dcd388aab6a4 100644 --- a/crates/welcome/Cargo.toml +++ b/crates/welcome/Cargo.toml @@ -15,6 +15,7 @@ anyhow = "1.0.38" log = "0.4" editor = { path = "../editor" } gpui = { path = "../gpui" } +install_cli = { path = "../install_cli" } project = { path = "../project" } settings = { path = "../settings" } theme = { path = "../theme" } diff --git a/crates/welcome/src/welcome.rs b/crates/welcome/src/welcome.rs index c24e0b5b24ccd1cf61f5bf24c26969ba0bd040a2..c6316c61d50264c74ad4f9da6847d89c9342643a 100644 --- a/crates/welcome/src/welcome.rs +++ b/crates/welcome/src/welcome.rs @@ -66,6 +66,7 @@ impl View for WelcomePage { .boxed(), self.render_cta_button(2, "Choose a theme", theme_selector::Toggle, width, cx), self.render_cta_button(3, "Choose a keymap", theme_selector::Toggle, width, cx), + self.render_cta_button(4, "Install the CLI", install_cli::Install, width, cx), self.render_settings_checkbox::( "Do you want to send telemetry?", &theme.welcome.checkbox, diff --git a/crates/workspace/Cargo.toml b/crates/workspace/Cargo.toml index fc069fe6c8d7d481873a22ebc6b679b1aba85632..2ba7a6cc40b31e6fbe72862f2fbc85ef8d60a2ee 100644 --- a/crates/workspace/Cargo.toml +++ b/crates/workspace/Cargo.toml @@ -27,6 +27,7 @@ context_menu = { path = "../context_menu" } drag_and_drop = { path = "../drag_and_drop" } fs = { path = "../fs" } gpui = { path = "../gpui" } +install_cli = { path = "../install_cli" } language = { path = "../language" } menu = { path = "../menu" } project = { path = "../project" } diff --git a/crates/workspace/src/notifications.rs b/crates/workspace/src/notifications.rs index 141a345382603ea59c1699b008d2104deb4d18ae..76f46f83c5f87c88b8dd5c68e2e2d98e39798a79 100644 --- a/crates/workspace/src/notifications.rs +++ b/crates/workspace/src/notifications.rs @@ -122,6 +122,8 @@ impl Workspace { pub mod simple_message_notification { + use std::borrow::Cow; + use gpui::{ actions, elements::{Flex, MouseEventHandler, Padding, ParentElement, Svg, Text}, @@ -153,9 +155,9 @@ pub mod simple_message_notification { } pub struct MessageNotification { - message: String, + message: Cow<'static, str>, click_action: Option>, - click_message: Option, + click_message: Option>, } pub enum MessageNotificationEvent { @@ -167,23 +169,23 @@ pub mod simple_message_notification { } impl MessageNotification { - pub fn new_message>(message: S) -> MessageNotification { + pub fn new_message>>(message: S) -> MessageNotification { Self { - message: message.as_ref().to_string(), + message: message.into(), click_action: None, click_message: None, } } - pub fn new, A: Action, S2: AsRef>( + pub fn new>, A: Action, S2: Into>>( message: S1, click_action: A, click_message: S2, ) -> Self { Self { - message: message.as_ref().to_string(), + message: message.into(), click_action: Some(Box::new(click_action) as Box), - click_message: Some(click_message.as_ref().to_string()), + click_message: Some(click_message.into()), } } @@ -210,6 +212,8 @@ pub mod simple_message_notification { let click_message = self.click_message.as_ref().map(|message| message.clone()); let message = self.message.clone(); + let has_click_action = click_action.is_some(); + MouseEventHandler::::new(0, cx, |state, cx| { Flex::column() .with_child( @@ -243,6 +247,7 @@ pub mod simple_message_notification { .on_click(MouseButton::Left, move |_, cx| { cx.dispatch_action(CancelMessageNotification) }) + .with_cursor_style(CursorStyle::PointingHand) .aligned() .constrained() .with_height( @@ -272,12 +277,19 @@ pub mod simple_message_notification { .contained() .boxed() }) - .with_cursor_style(CursorStyle::PointingHand) + // Since we're not using a proper overlay, we have to capture these extra events + .on_down(MouseButton::Left, |_, _| {}) + .on_up(MouseButton::Left, |_, _| {}) .on_click(MouseButton::Left, move |_, cx| { if let Some(click_action) = click_action.as_ref() { cx.dispatch_any_action(click_action.boxed_clone()) } }) + .with_cursor_style(if has_click_action { + CursorStyle::PointingHand + } else { + CursorStyle::Arrow + }) .boxed() } } diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index cd2cd6fccb3ffd1f5f7cfcab2ae8af76386d9c1a..234c40c69dff55d0279479564bb4175c63af90e5 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -17,7 +17,7 @@ mod toolbar; pub use smallvec; -use anyhow::{anyhow, Result}; +use anyhow::{anyhow, Result, Context}; use call::ActiveCall; use client::{ proto::{self, PeerId}, @@ -65,7 +65,7 @@ use crate::{ }; use lazy_static::lazy_static; use log::{error, warn}; -use notifications::NotificationHandle; +use notifications::{NotificationHandle, NotifyResultExt}; pub use pane::*; pub use pane_group::*; use persistence::{model::SerializedItem, DB}; @@ -267,6 +267,28 @@ pub fn init(app_state: Arc, cx: &mut MutableAppContext) { }) }, ); + + cx.add_action(|_: &mut Workspace, _: &install_cli::Install, cx| { + cx.spawn(|workspace, mut cx| async move { + let err = install_cli::install_cli(&cx).await.context("Failed to create CLI symlink"); + + cx.update(|cx| { + workspace.update(cx, |workspace, cx| { + if matches!(err, Err(_)) { + err.notify_err(workspace, cx); + } else { + workspace.show_notification(1, cx, |cx| { + cx.add_view(|_| MessageNotification::new_message("Successfully installed the 'zed' binary")) + }); + } + }) + }) + + }).detach(); + + + + }); let client = &app_state.client; client.add_view_request_handler(Workspace::handle_follow); diff --git a/crates/zed/Cargo.toml b/crates/zed/Cargo.toml index 68b04c7e2f846f549837f6aa7b77d1857d2243c3..8589af77e0dfbf8e049749ec56138dd28ac40f38 100644 --- a/crates/zed/Cargo.toml +++ b/crates/zed/Cargo.toml @@ -39,6 +39,7 @@ fsevent = { path = "../fsevent" } fuzzy = { path = "../fuzzy" } go_to_line = { path = "../go_to_line" } gpui = { path = "../gpui" } +install_cli = { path = "../install_cli" } journal = { path = "../journal" } language = { path = "../language" } lsp = { path = "../lsp" } diff --git a/crates/zed/src/menus.rs b/crates/zed/src/menus.rs index bb519c7a9505bc2de07fa60c70014be3b4fbc169..9381a909075b72364789e765600fd25885827f02 100644 --- a/crates/zed/src/menus.rs +++ b/crates/zed/src/menus.rs @@ -19,7 +19,7 @@ pub fn menus() -> Vec> { MenuItem::action("Select Theme", theme_selector::Toggle), ], }), - MenuItem::action("Install CLI", super::InstallCommandLineInterface), + MenuItem::action("Install CLI", install_cli::Install), MenuItem::separator(), MenuItem::action("Hide Zed", super::Hide), MenuItem::action("Hide Others", super::HideOthers), diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index a9032a264ba8e8fbfc9e3f505ae313038b8e7053..71e4b48db381112bbf6390cc78d58459ba158056 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -2,7 +2,7 @@ pub mod languages; pub mod menus; #[cfg(any(test, feature = "test-support"))] pub mod test; -use anyhow::{anyhow, Context, Result}; +use anyhow::Context; use assets::Assets; use breadcrumbs::Breadcrumbs; pub use client; @@ -21,7 +21,7 @@ use gpui::{ geometry::vector::vec2f, impl_actions, platform::{WindowBounds, WindowOptions}, - AssetSource, AsyncAppContext, Platform, PromptLevel, TitlebarOptions, ViewContext, WindowKind, + AssetSource, Platform, PromptLevel, TitlebarOptions, ViewContext, WindowKind, }; use language::Rope; pub use lsp; @@ -68,7 +68,6 @@ actions!( IncreaseBufferFontSize, DecreaseBufferFontSize, ResetBufferFontSize, - InstallCommandLineInterface, ResetDatabase, WelcomeExperience ] @@ -144,8 +143,8 @@ pub fn init(app_state: &Arc, cx: &mut gpui::MutableAppContext) { cx.refresh_windows(); }); }); - cx.add_global_action(move |_: &InstallCommandLineInterface, cx| { - cx.spawn(|cx| async move { install_cli(&cx).await.context("error creating CLI symlink") }) + cx.add_global_action(move |_: &install_cli::Install, cx| { + cx.spawn(|cx| async move { install_cli::install_cli(&cx).await.context("error creating CLI symlink") }) .detach_and_log_err(cx); }); cx.add_action({ @@ -505,54 +504,6 @@ fn about(_: &mut Workspace, _: &About, cx: &mut gpui::ViewContext) { ); } -async fn install_cli(cx: &AsyncAppContext) -> Result<()> { - let cli_path = cx.platform().path_for_auxiliary_executable("cli")?; - let link_path = Path::new("/usr/local/bin/zed"); - let bin_dir_path = link_path.parent().unwrap(); - - // Don't re-create symlink if it points to the same CLI binary. - if smol::fs::read_link(link_path).await.ok().as_ref() == Some(&cli_path) { - return Ok(()); - } - - // If the symlink is not there or is outdated, first try replacing it - // without escalating. - smol::fs::remove_file(link_path).await.log_err(); - if smol::fs::unix::symlink(&cli_path, link_path) - .await - .log_err() - .is_some() - { - return Ok(()); - } - - // The symlink could not be created, so use osascript with admin privileges - // to create it. - let status = smol::process::Command::new("osascript") - .args([ - "-e", - &format!( - "do shell script \" \ - mkdir -p \'{}\' && \ - ln -sf \'{}\' \'{}\' \ - \" with administrator privileges", - bin_dir_path.to_string_lossy(), - cli_path.to_string_lossy(), - link_path.to_string_lossy(), - ), - ]) - .stdout(smol::process::Stdio::inherit()) - .stderr(smol::process::Stdio::inherit()) - .output() - .await? - .status; - if status.success() { - Ok(()) - } else { - Err(anyhow!("error running osascript")) - } -} - fn open_config_file( path: &'static Path, app_state: Arc, From 3b31f10c6f5c636a23dd172813be64f632298739 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Mon, 6 Mar 2023 18:36:18 -0800 Subject: [PATCH 20/93] Made the theme picker sort from dark to light Added a layer into 'ConstrainedBox' to clip it 's children Made the welcome experience responsive to small and large sizes --- crates/gpui/src/elements/constrained_box.rs | 4 +++- crates/picker/src/picker.rs | 5 ++++- crates/theme_selector/src/theme_selector.rs | 1 - crates/welcome/src/welcome.rs | 3 ++- 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/crates/gpui/src/elements/constrained_box.rs b/crates/gpui/src/elements/constrained_box.rs index 2e232c6197774861fd14a453e62a8efb5772ee53..e4d51f5730be1bfa190ac7f2a7aa9e5e49b630e9 100644 --- a/crates/gpui/src/elements/constrained_box.rs +++ b/crates/gpui/src/elements/constrained_box.rs @@ -153,7 +153,9 @@ impl Element for ConstrainedBox { _: &mut Self::LayoutState, cx: &mut PaintContext, ) -> Self::PaintState { - self.child.paint(bounds.origin(), visible_bounds, cx); + cx.paint_layer(Some(visible_bounds), |cx| { + self.child.paint(bounds.origin(), visible_bounds, cx); + }) } fn rect_for_text_range( diff --git a/crates/picker/src/picker.rs b/crates/picker/src/picker.rs index e4d062d575aa6a44909d0a757c766470987abb87..fe4b75dbefae3abfe21db7bc1c48ad1bda6f9e6c 100644 --- a/crates/picker/src/picker.rs +++ b/crates/picker/src/picker.rs @@ -102,7 +102,10 @@ impl View for Picker { .read(cx) .render_match(ix, state, ix == selected_ix, cx) }) - .on_down(MouseButton::Left, move |_, cx| { + // Capture mouse events + .on_down(MouseButton::Left, |_, _| {}) + .on_up(MouseButton::Left, |_, _| {}) + .on_click(MouseButton::Left, move |_, cx| { cx.dispatch_action(SelectIndex(ix)) }) .with_cursor_style(CursorStyle::PointingHand) diff --git a/crates/theme_selector/src/theme_selector.rs b/crates/theme_selector/src/theme_selector.rs index d999730a0d8b7abe21c0d9b39bfc3a9fb4ca49ca..0930bf0484e9a28880035c058ff2238c53324c5f 100644 --- a/crates/theme_selector/src/theme_selector.rs +++ b/crates/theme_selector/src/theme_selector.rs @@ -50,7 +50,6 @@ impl ThemeSelector { theme_names.sort_unstable_by(|a, b| { a.is_light .cmp(&b.is_light) - .reverse() .then(a.name.cmp(&b.name)) }); let matches = theme_names diff --git a/crates/welcome/src/welcome.rs b/crates/welcome/src/welcome.rs index c6316c61d50264c74ad4f9da6847d89c9342643a..dc864a3ad17db2e7856eb8fa0174ccce724eb836 100644 --- a/crates/welcome/src/welcome.rs +++ b/crates/welcome/src/welcome.rs @@ -84,6 +84,7 @@ impl View for WelcomePage { ]) .constrained() .with_max_width(width) + .contained().with_uniform_padding(10.) .aligned() .boxed(), ) @@ -126,7 +127,7 @@ impl WelcomePage { .contained() .with_style(style.container) .constrained() - .with_width(width) + .with_max_width(width) .boxed() }) .on_click(MouseButton::Left, move |_, cx| { From 1e5aff9e5167038b28ebd040a48d3a3c858ac73b Mon Sep 17 00:00:00 2001 From: Julia Date: Tue, 7 Mar 2023 12:23:18 -0500 Subject: [PATCH 21/93] Update collab integration test to new reconnect timeout --- crates/collab/src/tests/integration_tests.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/collab/src/tests/integration_tests.rs b/crates/collab/src/tests/integration_tests.rs index 1ab78ac310b0d23b10f08af62fbe8490f626161b..28266824e388ec4e5d88a26e88b14d918e929af7 100644 --- a/crates/collab/src/tests/integration_tests.rs +++ b/crates/collab/src/tests/integration_tests.rs @@ -829,7 +829,7 @@ async fn test_server_restarts( // Users A and B reconnect to the call. User C has troubles reconnecting, so it leaves the room. client_c.override_establish_connection(|_, cx| cx.spawn(|_| future::pending())); - deterministic.advance_clock(RECEIVE_TIMEOUT); + deterministic.advance_clock(RECONNECT_TIMEOUT); assert_eq!( room_participants(&room_a, cx_a), RoomParticipants { @@ -1001,7 +1001,7 @@ async fn test_server_restarts( client_a.override_establish_connection(|_, cx| cx.spawn(|_| future::pending())); client_b.override_establish_connection(|_, cx| cx.spawn(|_| future::pending())); client_c.override_establish_connection(|_, cx| cx.spawn(|_| future::pending())); - deterministic.advance_clock(RECEIVE_TIMEOUT); + deterministic.advance_clock(RECONNECT_TIMEOUT); assert_eq!( room_participants(&room_a, cx_a), RoomParticipants { From 19fc14320997a29ad3af2f5d89fe0b339dffebb1 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Tue, 7 Mar 2023 12:19:51 -0800 Subject: [PATCH 22/93] Add base keymap setting Format all files Co-Authored-by: Nathan --- assets/keymaps/atom.json | 68 ++++++++++++++++++ assets/keymaps/jetbrains.json | 78 +++++++++++++++++++++ assets/keymaps/sublime_text.json | 60 ++++++++++++++++ crates/install_cli/src/install_cli.rs | 9 ++- crates/settings/src/keymap_file.rs | 6 +- crates/settings/src/settings.rs | 24 +++++++ crates/settings/src/watched_json.rs | 31 ++++++-- crates/theme_selector/src/theme_selector.rs | 6 +- crates/welcome/src/welcome.rs | 8 ++- crates/workspace/src/workspace.rs | 23 +++--- crates/zed/src/main.rs | 13 ++-- crates/zed/src/zed.rs | 10 ++- 12 files changed, 301 insertions(+), 35 deletions(-) create mode 100644 assets/keymaps/atom.json create mode 100644 assets/keymaps/jetbrains.json create mode 100644 assets/keymaps/sublime_text.json diff --git a/assets/keymaps/atom.json b/assets/keymaps/atom.json new file mode 100644 index 0000000000000000000000000000000000000000..766c46c133df9b617061694b9eb23ad8fecaceb8 --- /dev/null +++ b/assets/keymaps/atom.json @@ -0,0 +1,68 @@ +[ + { + "bindings": { + "cmd-k cmd-p": "workspace::ActivatePreviousPane", + "cmd-k cmd-n": "workspace::ActivateNextPane" + } + }, + { + "context": "Editor", + "bindings": { + "cmd-b": "editor::GoToDefinition", + "cmd-<": "editor::ScrollCursorCenter", + "cmd-g": [ + "editor::SelectNext", + { + "replace_newest": true + } + ], + "ctrl-shift-down": "editor::AddSelectionBelow", + "ctrl-shift-up": "editor::AddSelectionAbove", + "cmd-shift-backspace": "editor::DeleteToBeginningOfLine" + } + }, + { + "context": "Editor && mode == full", + "bindings": { + "cmd-r": "outline::Toggle" + } + }, + { + "context": "BufferSearchBar", + "bindings": { + "cmd-f3": "search::SelectNextMatch", + "cmd-shift-f3": "search::SelectPrevMatch" + } + }, + { + "context": "Workspace", + "bindings": { + "cmd-\\": "workspace::ToggleLeftSidebar", + "cmd-k cmd-b": "workspace::ToggleLeftSidebar", + "cmd-t": "file_finder::Toggle", + "cmd-shift-r": "project_symbols::Toggle" + } + }, + { + "context": "Pane", + "bindings": { + "alt-cmd-/": "search::ToggleRegex", + "ctrl-0": "project_panel::ToggleFocus" + } + }, + { + "context": "ProjectPanel", + "bindings": { + "ctrl-[": "project_panel::CollapseSelectedEntry", + "ctrl-b": "project_panel::CollapseSelectedEntry", + "h": "project_panel::CollapseSelectedEntry", + "ctrl-]": "project_panel::ExpandSelectedEntry", + "ctrl-f": "project_panel::ExpandSelectedEntry", + "ctrl-shift-c": "project_panel::CopyPath" + } + }, + { + "context": "Dock", + "bindings": {} + } +] \ No newline at end of file diff --git a/assets/keymaps/jetbrains.json b/assets/keymaps/jetbrains.json new file mode 100644 index 0000000000000000000000000000000000000000..2e6e5e77e6abebd3d6c464895af5cdcaa9dc2075 --- /dev/null +++ b/assets/keymaps/jetbrains.json @@ -0,0 +1,78 @@ +[ + { + "bindings": { + "cmd-shift-[": "pane::ActivatePrevItem", + "cmd-shift-]": "pane::ActivateNextItem" + } + }, + { + "context": "Editor", + "bindings": { + "ctrl->": "zed::IncreaseBufferFontSize", + "ctrl-<": "zed::DecreaseBufferFontSize", + "cmd-d": "editor::DuplicateLine", + "cmd-pagedown": "editor::MovePageDown", + "cmd-pageup": "editor::MovePageUp", + "ctrl-alt-shift-b": "editor::SelectToPreviousWordStart", + "shift-enter": "editor::NewlineBelow", + "cmd--": "editor::Fold", + "cmd-=": "editor::UnfoldLines", + "alt-shift-g": "editor::SplitSelectionIntoLines", + "ctrl-g": [ + "editor::SelectNext", + { + "replace_newest": false + } + ], + "cmd-/": [ + "editor::ToggleComments", + { + "advance_downwards": true + } + ], + "shift-alt-up": "editor::MoveLineUp", + "shift-alt-down": "editor::MoveLineDown", + "cmd-[": "pane::GoBack", + "cmd-]": "pane::GoForward", + "alt-f7": "editor::FindAllReferences", + "cmd-alt-f7": "editor::FindAllReferences", + "cmd-b": "editor::GoToDefinition", + "cmd-alt-b": "editor::GoToDefinition", + "cmd-shift-b": "editor::GoToTypeDefinition", + "alt-enter": "editor::ToggleCodeActions", + "f2": "editor::GoToDiagnostic", + "cmd-f2": "editor::GoToPrevDiagnostic", + "ctrl-alt-shift-down": "editor::GoToHunk", + "ctrl-alt-shift-up": "editor::GoToPrevHunk", + "cmd-home": "editor::MoveToBeginning", + "cmd-end": "editor::MoveToEnd", + "cmd-shift-home": "editor::SelectToBeginning", + "cmd-shift-end": "editor::SelectToEnd" + } + }, + { + "context": "Editor && mode == full", + "bindings": { + "cmd-f12": "outline::Toggle", + "cmd-7": "outline::Toggle", + "cmd-shift-o": "file_finder::Toggle", + "cmd-l": "go_to_line::Toggle" + } + }, + { + "context": "Workspace", + "bindings": { + "cmd-shift-a": "command_palette::Toggle", + "cmd-alt-o": "project_symbols::Toggle", + "cmd-1": "workspace::ToggleLeftSidebar", + "cmd-6": "diagnostics::Deploy", + "alt-f12": "dock::FocusDock" + } + }, + { + "context": "Dock", + "bindings": { + "alt-f12": "dock::HideDock" + } + } +] \ No newline at end of file diff --git a/assets/keymaps/sublime_text.json b/assets/keymaps/sublime_text.json new file mode 100644 index 0000000000000000000000000000000000000000..1d3dd887d7b4a57add7d5be95d34700e1be1143a --- /dev/null +++ b/assets/keymaps/sublime_text.json @@ -0,0 +1,60 @@ +[ + { + "bindings": { + "cmd-shift-[": "pane::ActivatePrevItem", + "cmd-shift-]": "pane::ActivateNextItem", + "ctrl-pagedown": "pane::ActivatePrevItem", + "ctrl-pageup": "pane::ActivateNextItem", + "ctrl-shift-tab": "pane::ActivateNextItem", + "ctrl-tab": "pane::ActivatePrevItem", + "cmd-+": "zed::IncreaseBufferFontSize" + } + }, + { + "context": "Editor", + "bindings": { + "ctrl-shift-up": "editor::AddSelectionAbove", + "ctrl-shift-down": "editor::AddSelectionBelow", + "cmd-shift-space": "editor::SelectAll", + "ctrl-shift-m": "editor::SelectLargerSyntaxNode", + "cmd-shift-a": "editor::SelectLargerSyntaxNode", + "shift-f12": "editor::FindAllReferences", + "alt-cmd-down": "editor::GoToDefinition", + "alt-shift-cmd-down": "editor::FindAllReferences", + "ctrl-.": "editor::GoToHunk", + "ctrl-,": "editor::GoToPrevHunk", + "ctrl-backspace": "editor::DeleteToPreviousWordStart", + "ctrl-delete": "editor::DeleteToNextWordEnd" + } + }, + { + "context": "Editor && mode == full", + "bindings": { + "cmd-r": "outline::Toggle" + } + }, + { + "context": "Pane", + "bindings": { + "f4": "search::SelectNextMatch", + "shift-f4": "search::SelectPrevMatch" + } + }, + { + "context": "Workspace", + "bindings": { + "ctrl-`": "dock::FocusDock", + "cmd-k cmd-b": "workspace::ToggleLeftSidebar", + "cmd-t": "file_finder::Toggle", + "shift-cmd-r": "project_symbols::Toggle", + // Currently busted: https://github.com/zed-industries/feedback/issues/898 + "ctrl-0": "project_panel::ToggleFocus" + } + }, + { + "context": "Dock", + "bindings": { + "ctrl-`": "dock::HideDock" + } + } +] \ No newline at end of file diff --git a/crates/install_cli/src/install_cli.rs b/crates/install_cli/src/install_cli.rs index 06561a28f8b6e04c13ef65f1400cbfef858d4db8..adf50586d759ae24f39e3187b080a30d894f8eec 100644 --- a/crates/install_cli/src/install_cli.rs +++ b/crates/install_cli/src/install_cli.rs @@ -1,11 +1,10 @@ use std::path::Path; -use anyhow::{Result, anyhow}; -use gpui::{AsyncAppContext, actions}; +use anyhow::{anyhow, Result}; +use gpui::{actions, AsyncAppContext}; use util::ResultExt; -actions!(cli, [ Install ]); - +actions!(cli, [Install]); pub async fn install_cli(cx: &AsyncAppContext) -> Result<()> { let cli_path = cx.platform().path_for_auxiliary_executable("cli")?; @@ -53,4 +52,4 @@ pub async fn install_cli(cx: &AsyncAppContext) -> Result<()> { } else { Err(anyhow!("error running osascript")) } -} \ No newline at end of file +} diff --git a/crates/settings/src/keymap_file.rs b/crates/settings/src/keymap_file.rs index 01992d94311e7dd348b06d3a7b6b042780204010..9048719d3f58c9bb3dc91e08d4275e551e0c7b15 100644 --- a/crates/settings/src/keymap_file.rs +++ b/crates/settings/src/keymap_file.rs @@ -1,4 +1,4 @@ -use crate::parse_json_with_comments; +use crate::{parse_json_with_comments, Settings}; use anyhow::{Context, Result}; use assets::Assets; use collections::BTreeMap; @@ -45,6 +45,10 @@ impl KeymapFileContent { for path in ["keymaps/default.json", "keymaps/vim.json"] { Self::load(path, cx).unwrap(); } + + if let Some(base_keymap) = cx.global::().base_keymap { + Self::load(base_keymap.asset_path(), cx).log_err(); + } } pub fn load(asset_path: &str, cx: &mut MutableAppContext) -> Result<()> { diff --git a/crates/settings/src/settings.rs b/crates/settings/src/settings.rs index 501a88c42e14bcb3da9cadaa3f889a63580830df..ae6742894899f19c4f738bbee1a563a81858b2eb 100644 --- a/crates/settings/src/settings.rs +++ b/crates/settings/src/settings.rs @@ -24,6 +24,7 @@ use tree_sitter::Query; use util::ResultExt as _; pub use keymap_file::{keymap_file_json_schema, KeymapFileContent}; +pub use watched_json::watch_files; #[derive(Clone)] pub struct Settings { @@ -54,6 +55,24 @@ pub struct Settings { pub telemetry_defaults: TelemetrySettings, pub telemetry_overrides: TelemetrySettings, pub auto_update: bool, + pub base_keymap: Option, +} + +#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] +pub enum BaseKeymap { + JetBrains, + Sublime, + Atom, +} + +impl BaseKeymap { + pub fn asset_path(&self) -> &str { + match self { + BaseKeymap::JetBrains => "keymaps/jetbrains.json", + BaseKeymap::Sublime => "keymaps/sublime_text.json", + BaseKeymap::Atom => "keymaps/atom.json", + } + } } #[derive(Copy, Clone, Debug, Default, Serialize, Deserialize, JsonSchema)] @@ -326,6 +345,8 @@ pub struct SettingsFileContent { pub telemetry: TelemetrySettings, #[serde(default)] pub auto_update: Option, + #[serde(default)] + pub base_keymap: Option, } #[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)] @@ -396,6 +417,7 @@ impl Settings { telemetry_defaults: defaults.telemetry, telemetry_overrides: Default::default(), auto_update: defaults.auto_update.unwrap(), + base_keymap: Default::default(), } } @@ -433,6 +455,7 @@ impl Settings { merge(&mut self.vim_mode, data.vim_mode); merge(&mut self.autosave, data.autosave); merge(&mut self.default_dock_anchor, data.default_dock_anchor); + merge(&mut self.base_keymap, Some(data.base_keymap)); // Ensure terminal font is loaded, so we can request it in terminal_element layout if let Some(terminal_font) = &data.terminal.font_family { @@ -610,6 +633,7 @@ impl Settings { }, telemetry_overrides: Default::default(), auto_update: true, + base_keymap: None, } } diff --git a/crates/settings/src/watched_json.rs b/crates/settings/src/watched_json.rs index e304842aa2127cba2b3d25f533b9e7c19c71a8d9..c4cc64cd620542548d3d17ea830d5f84db63b8cf 100644 --- a/crates/settings/src/watched_json.rs +++ b/crates/settings/src/watched_json.rs @@ -62,7 +62,18 @@ where } } -pub fn watch_settings_file( +pub fn watch_files( + defaults: Settings, + settings_file: WatchedJsonFile, + theme_registry: Arc, + keymap_file: WatchedJsonFile, + cx: &mut MutableAppContext, +) { + watch_settings_file(defaults, settings_file, theme_registry, cx); + watch_keymap_file(keymap_file, cx); +} + +pub(crate) fn watch_settings_file( defaults: Settings, mut file: WatchedJsonFile, theme_registry: Arc, @@ -77,13 +88,13 @@ pub fn watch_settings_file( .detach(); } -pub fn keymap_updated(content: KeymapFileContent, cx: &mut MutableAppContext) { +fn keymap_updated(content: KeymapFileContent, cx: &mut MutableAppContext) { cx.clear_bindings(); KeymapFileContent::load_defaults(cx); content.add_to_cx(cx).log_err(); } -pub fn settings_updated( +fn settings_updated( defaults: &Settings, content: SettingsFileContent, theme_registry: &Arc, @@ -95,10 +106,20 @@ pub fn settings_updated( cx.refresh_windows(); } -pub fn watch_keymap_file(mut file: WatchedJsonFile, cx: &mut MutableAppContext) { +fn watch_keymap_file(mut file: WatchedJsonFile, cx: &mut MutableAppContext) { cx.spawn(|mut cx| async move { + let mut settings_subscription = None; while let Some(content) = file.0.recv().await { - cx.update(|cx| keymap_updated(content, cx)); + cx.update(|cx| { + let old_base_keymap = cx.global::().base_keymap; + keymap_updated(content.clone(), cx); + settings_subscription = Some(cx.observe_global::(move |cx| { + let settings = cx.global::(); + if settings.base_keymap != old_base_keymap { + keymap_updated(content.clone(), cx); + } + })); + }); } }) .detach(); diff --git a/crates/theme_selector/src/theme_selector.rs b/crates/theme_selector/src/theme_selector.rs index 0930bf0484e9a28880035c058ff2238c53324c5f..ae3278b7111c8e903293723759a1e8fd238a8697 100644 --- a/crates/theme_selector/src/theme_selector.rs +++ b/crates/theme_selector/src/theme_selector.rs @@ -47,11 +47,7 @@ impl ThemeSelector { let mut theme_names = registry .list(**cx.default_global::()) .collect::>(); - theme_names.sort_unstable_by(|a, b| { - a.is_light - .cmp(&b.is_light) - .then(a.name.cmp(&b.name)) - }); + theme_names.sort_unstable_by(|a, b| a.is_light.cmp(&b.is_light).then(a.name.cmp(&b.name))); let matches = theme_names .iter() .map(|meta| StringMatch { diff --git a/crates/welcome/src/welcome.rs b/crates/welcome/src/welcome.rs index dc864a3ad17db2e7856eb8fa0174ccce724eb836..8bb055dad0a7c333f4b590a286d0d6e90baf0ec9 100644 --- a/crates/welcome/src/welcome.rs +++ b/crates/welcome/src/welcome.rs @@ -84,7 +84,8 @@ impl View for WelcomePage { ]) .constrained() .with_max_width(width) - .contained().with_uniform_padding(10.) + .contained() + .with_uniform_padding(10.) .aligned() .boxed(), ) @@ -174,7 +175,10 @@ impl WelcomePage { } }) .boxed(), - Label::new(label, style.label.text.clone()).contained().with_style(style.label.container).boxed(), + Label::new(label, style.label.text.clone()) + .contained() + .with_style(style.label.container) + .boxed(), ]) .align_children_center() .boxed() diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index 234c40c69dff55d0279479564bb4175c63af90e5..e74bcdc1773d3caac4f3f9724607f93e2240736e 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -17,7 +17,7 @@ mod toolbar; pub use smallvec; -use anyhow::{anyhow, Result, Context}; +use anyhow::{anyhow, Context, Result}; use call::ActiveCall; use client::{ proto::{self, PeerId}, @@ -267,27 +267,30 @@ pub fn init(app_state: Arc, cx: &mut MutableAppContext) { }) }, ); - + cx.add_action(|_: &mut Workspace, _: &install_cli::Install, cx| { cx.spawn(|workspace, mut cx| async move { - let err = install_cli::install_cli(&cx).await.context("Failed to create CLI symlink"); - + let err = install_cli::install_cli(&cx) + .await + .context("Failed to create CLI symlink"); + cx.update(|cx| { workspace.update(cx, |workspace, cx| { if matches!(err, Err(_)) { err.notify_err(workspace, cx); } else { workspace.show_notification(1, cx, |cx| { - cx.add_view(|_| MessageNotification::new_message("Successfully installed the 'zed' binary")) + cx.add_view(|_| { + MessageNotification::new_message( + "Successfully installed the `zed` binary", + ) + }) }); } }) }) - - }).detach(); - - - + }) + .detach(); }); let client = &app_state.client; diff --git a/crates/zed/src/main.rs b/crates/zed/src/main.rs index a9625bf78ee81e2d73e6a071f361e15dc12dd975..8407bd45167e239f950c3c987a21bd3c7f92a266 100644 --- a/crates/zed/src/main.rs +++ b/crates/zed/src/main.rs @@ -38,7 +38,7 @@ use std::{ use terminal_view::{get_working_directory, TerminalView}; use fs::RealFs; -use settings::watched_json::{watch_keymap_file, watch_settings_file, WatchedJsonFile}; +use settings::watched_json::WatchedJsonFile; use theme::ThemeRegistry; #[cfg(debug_assertions)] use util::StaffMode; @@ -123,7 +123,14 @@ fn main() { fs.clone(), )); - watch_settings_file(default_settings, settings_file_content, themes.clone(), cx); + settings::watch_files( + default_settings, + settings_file_content, + themes.clone(), + keymap_file, + cx, + ); + if !stdout_is_a_pty() { upload_previous_panics(http.clone(), cx); } @@ -136,8 +143,6 @@ fn main() { languages::init(languages.clone()); let user_store = cx.add_model(|cx| UserStore::new(client.clone(), http.clone(), cx)); - watch_keymap_file(keymap_file, cx); - cx.set_global(client.clone()); context_menu::init(cx); diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index 71e4b48db381112bbf6390cc78d58459ba158056..2fb956f5b6f6ce2c26e5ce0782024c4e367e6bfa 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -21,7 +21,7 @@ use gpui::{ geometry::vector::vec2f, impl_actions, platform::{WindowBounds, WindowOptions}, - AssetSource, Platform, PromptLevel, TitlebarOptions, ViewContext, WindowKind, + AssetSource, Platform, PromptLevel, TitlebarOptions, ViewContext, WindowKind, }; use language::Rope; pub use lsp; @@ -144,8 +144,12 @@ pub fn init(app_state: &Arc, cx: &mut gpui::MutableAppContext) { }); }); cx.add_global_action(move |_: &install_cli::Install, cx| { - cx.spawn(|cx| async move { install_cli::install_cli(&cx).await.context("error creating CLI symlink") }) - .detach_and_log_err(cx); + cx.spawn(|cx| async move { + install_cli::install_cli(&cx) + .await + .context("error creating CLI symlink") + }) + .detach_and_log_err(cx); }); cx.add_action({ let app_state = app_state.clone(); From 477453c3962ff26f41a7530f462f42e2cf0323eb Mon Sep 17 00:00:00 2001 From: Nate Butler Date: Tue, 7 Mar 2023 13:22:07 -0800 Subject: [PATCH 23/93] Update existing Atelier themes --- styles/src/themes/atelier-cave-dark.ts | 55 ++++++++++++++++ styles/src/themes/atelier-cave-light.ts | 55 ++++++++++++++++ styles/src/themes/atelier-cave.ts | 65 ------------------ styles/src/themes/atelier-sulphurpool-dark.ts | 55 ++++++++++++++++ .../src/themes/atelier-sulphurpool-light.ts | 55 ++++++++++++++++ styles/src/themes/atelier-sulphurpool.ts | 45 ------------- styles/src/themes/common/atelier-common.ts | 66 +++++++++++++++++++ 7 files changed, 286 insertions(+), 110 deletions(-) create mode 100644 styles/src/themes/atelier-cave-dark.ts create mode 100644 styles/src/themes/atelier-cave-light.ts delete mode 100644 styles/src/themes/atelier-cave.ts create mode 100644 styles/src/themes/atelier-sulphurpool-dark.ts create mode 100644 styles/src/themes/atelier-sulphurpool-light.ts delete mode 100644 styles/src/themes/atelier-sulphurpool.ts create mode 100644 styles/src/themes/common/atelier-common.ts diff --git a/styles/src/themes/atelier-cave-dark.ts b/styles/src/themes/atelier-cave-dark.ts new file mode 100644 index 0000000000000000000000000000000000000000..6cb8946b7ac1ddcec8f99c8966eebb5731a79b26 --- /dev/null +++ b/styles/src/themes/atelier-cave-dark.ts @@ -0,0 +1,55 @@ +import chroma from "chroma-js" +import { Meta } from "./common/colorScheme" +import { colorRamp, createColorScheme } from "./common/ramps" +import { metaCommon, name, buildSyntax, Variant } from "./common/atelier-common" + +const variant: Variant = { + meta: { + name: `${name} Cave Dark`, + ...metaCommon, + url: "https://atelierbram.github.io/syntax-highlighting/atelier-schemes/cave/", + }, + colors: { + base00: "#19171c", + base01: "#26232a", + base02: "#585260", + base03: "#655f6d", + base04: "#7e7887", + base05: "#8b8792", + base06: "#e2dfe7", + base07: "#efecf4", + base08: "#be4678", + base09: "#aa573c", + base0A: "#a06e3b", + base0B: "#2a9292", + base0C: "#398bc6", + base0D: "#576ddb", + base0E: "#955ae7", + base0F: "#bf40bf" + } +} + +const syntax = buildSyntax(variant) + +const theme = (variant: Variant) => { + const { meta, colors } = variant + + return createColorScheme(meta.name, false, { + neutral: chroma + .scale([ + colors.base00, colors.base01, colors.base02, colors.base03, colors.base04, colors.base05, colors.base06, colors.base07 + ]), + red: colorRamp(chroma(colors.base08)), + orange: colorRamp(chroma(colors.base09)), + yellow: colorRamp(chroma(colors.base0A)), + green: colorRamp(chroma(colors.base0B)), + cyan: colorRamp(chroma(colors.base0C)), + blue: colorRamp(chroma(colors.base0D)), + violet: colorRamp(chroma(colors.base0E)), + magenta: colorRamp(chroma(colors.base0F)), + }, syntax) +} + +export const dark = theme(variant) + +export const meta: Meta = variant.meta diff --git a/styles/src/themes/atelier-cave-light.ts b/styles/src/themes/atelier-cave-light.ts new file mode 100644 index 0000000000000000000000000000000000000000..b05f730f83283a9bf76dbf169b529caf50a66ffd --- /dev/null +++ b/styles/src/themes/atelier-cave-light.ts @@ -0,0 +1,55 @@ +import chroma from "chroma-js" +import { Meta } from "./common/colorScheme" +import { colorRamp, createColorScheme } from "./common/ramps" +import { metaCommon, name, buildSyntax, Variant } from "./common/atelier-common" + +const variant: Variant = { + meta: { + name: `${name} Cave Light`, + ...metaCommon, + url: "https://atelierbram.github.io/syntax-highlighting/atelier-schemes/cave/", + }, + colors: { + base00: "#efecf4", + base01: "#e2dfe7", + base02: "#8b8792", + base03: "#7e7887", + base04: "#655f6d", + base05: "#585260", + base06: "#26232a", + base07: "#19171c", + base08: "#be4678", + base09: "#aa573c", + base0A: "#a06e3b", + base0B: "#2a9292", + base0C: "#398bc6", + base0D: "#576ddb", + base0E: "#955ae7", + base0F: "#bf40bf" + } +} + +const syntax = buildSyntax(variant) + +const theme = (variant: Variant) => { + const { meta, colors } = variant + + return createColorScheme(meta.name, true, { + neutral: chroma + .scale([ + colors.base00, colors.base01, colors.base02, colors.base03, colors.base04, colors.base05, colors.base06, colors.base07 + ].reverse()), + red: colorRamp(chroma(colors.base08)), + orange: colorRamp(chroma(colors.base09)), + yellow: colorRamp(chroma(colors.base0A)), + green: colorRamp(chroma(colors.base0B)), + cyan: colorRamp(chroma(colors.base0C)), + blue: colorRamp(chroma(colors.base0D)), + violet: colorRamp(chroma(colors.base0E)), + magenta: colorRamp(chroma(colors.base0F)), + }, syntax) +} + +export const dark = theme(variant) + +export const meta: Meta = variant.meta diff --git a/styles/src/themes/atelier-cave.ts b/styles/src/themes/atelier-cave.ts deleted file mode 100644 index 21b846d708c349a8fa7b2779dd991ff5bcfa1605..0000000000000000000000000000000000000000 --- a/styles/src/themes/atelier-cave.ts +++ /dev/null @@ -1,65 +0,0 @@ -import chroma from "chroma-js" -import { Meta } from "./common/colorScheme" -import { colorRamp, createColorScheme } from "./common/ramps" - -const name = "Atelier Cave" - -export const dark = createColorScheme(`${name} Dark`, false, { - neutral: chroma - .scale([ - "#19171c", - "#26232a", - "#585260", - "#655f6d", - "#7e7887", - "#8b8792", - "#e2dfe7", - "#efecf4", - ]) - .domain([0, 0.15, 0.45, 0.6, 0.65, 0.7, 0.85, 1]), - red: colorRamp(chroma("#be4678")), - orange: colorRamp(chroma("#aa573c")), - yellow: colorRamp(chroma("#a06e3b")), - green: colorRamp(chroma("#2a9292")), - cyan: colorRamp(chroma("#398bc6")), - blue: colorRamp(chroma("#576ddb")), - violet: colorRamp(chroma("#955ae7")), - magenta: colorRamp(chroma("#bf40bf")), -}) - -export const light = createColorScheme(`${name} Light`, true, { - neutral: chroma - .scale([ - "#19171c", - "#26232a", - "#585260", - "#655f6d", - "#7e7887", - "#8b8792", - "#e2dfe7", - "#efecf4", - ]) - .correctLightness(), - red: colorRamp(chroma("#be4678")), - orange: colorRamp(chroma("#aa573c")), - yellow: colorRamp(chroma("#a06e3b")), - green: colorRamp(chroma("#2a9292")), - cyan: colorRamp(chroma("#398bc6")), - blue: colorRamp(chroma("#576ddb")), - violet: colorRamp(chroma("#955ae7")), - magenta: colorRamp(chroma("#bf40bf")), -}) - -export const meta: Meta = { - name, - author: "atelierbram", - license: { - SPDX: "MIT", - license_text: { - https_url: "https://atelierbram.mit-license.org/license.txt", - license_checksum: - "f95ce526ef4e7eecf7a832bba0e3451cc1000f9ce63eb01ed6f64f8109f5d0a5", - } - }, - url: "https://atelierbram.github.io/syntax-highlighting/atelier-schemes/cave/", -} diff --git a/styles/src/themes/atelier-sulphurpool-dark.ts b/styles/src/themes/atelier-sulphurpool-dark.ts new file mode 100644 index 0000000000000000000000000000000000000000..2d282deaa2b591b88a0e48f3c46eefe30528f31f --- /dev/null +++ b/styles/src/themes/atelier-sulphurpool-dark.ts @@ -0,0 +1,55 @@ +import chroma from "chroma-js" +import { Meta } from "./common/colorScheme" +import { colorRamp, createColorScheme } from "./common/ramps" +import { metaCommon, name, buildSyntax, Variant } from "./common/atelier-common" + +const variant: Variant = { + meta: { + name: `${name} Sulphurpool Dark`, + ...metaCommon, + url: "https://atelierbram.github.io/syntax-highlighting/atelier-schemes/sulphurpool/", + }, + colors: { + base00: "#202746", + base01: "#293256", + base02: "#5e6687", + base03: "#6b7394", + base04: "#898ea4", + base05: "#979db4", + base06: "#dfe2f1", + base07: "#f5f7ff", + base08: "#c94922", + base09: "#c76b29", + base0A: "#c08b30", + base0B: "#ac9739", + base0C: "#22a2c9", + base0D: "#3d8fd1", + base0E: "#6679cc", + base0F: "#9c637a" + } +} + +const syntax = buildSyntax(variant) + +const theme = (variant: Variant) => { + const { meta, colors } = variant + + return createColorScheme(meta.name, false, { + neutral: chroma + .scale([ + colors.base00, colors.base01, colors.base02, colors.base03, colors.base04, colors.base05, colors.base06, colors.base07 + ]), + red: colorRamp(chroma(colors.base08)), + orange: colorRamp(chroma(colors.base09)), + yellow: colorRamp(chroma(colors.base0A)), + green: colorRamp(chroma(colors.base0B)), + cyan: colorRamp(chroma(colors.base0C)), + blue: colorRamp(chroma(colors.base0D)), + violet: colorRamp(chroma(colors.base0E)), + magenta: colorRamp(chroma(colors.base0F)), + }, syntax) +} + +export const dark = theme(variant) + +export const meta: Meta = variant.meta diff --git a/styles/src/themes/atelier-sulphurpool-light.ts b/styles/src/themes/atelier-sulphurpool-light.ts new file mode 100644 index 0000000000000000000000000000000000000000..943ceedf2b3d582e2005fdc5e1c35d9536dab12e --- /dev/null +++ b/styles/src/themes/atelier-sulphurpool-light.ts @@ -0,0 +1,55 @@ +import chroma from "chroma-js" +import { Meta } from "./common/colorScheme" +import { colorRamp, createColorScheme } from "./common/ramps" +import { metaCommon, name, buildSyntax, Variant } from "./common/atelier-common" + +const variant: Variant = { + meta: { + name: `${name} Sulphurpool Light`, + ...metaCommon, + url: "https://atelierbram.github.io/syntax-highlighting/atelier-schemes/sulphurpool/", + }, + colors: { + base00: "#f5f7ff", + base01: "#dfe2f1", + base02: "#979db4", + base03: "#898ea4", + base04: "#6b7394", + base05: "#5e6687", + base06: "#293256", + base07: "#202746", + base08: "#c94922", + base09: "#c76b29", + base0A: "#c08b30", + base0B: "#ac9739", + base0C: "#22a2c9", + base0D: "#3d8fd1", + base0E: "#6679cc", + base0F: "#9c637a" + } +} + +const syntax = buildSyntax(variant) + +const theme = (variant: Variant) => { + const { meta, colors } = variant + + return createColorScheme(meta.name, true, { + neutral: chroma + .scale([ + colors.base00, colors.base01, colors.base02, colors.base03, colors.base04, colors.base05, colors.base06, colors.base07 + ].reverse()), + red: colorRamp(chroma(colors.base08)), + orange: colorRamp(chroma(colors.base09)), + yellow: colorRamp(chroma(colors.base0A)), + green: colorRamp(chroma(colors.base0B)), + cyan: colorRamp(chroma(colors.base0C)), + blue: colorRamp(chroma(colors.base0D)), + violet: colorRamp(chroma(colors.base0E)), + magenta: colorRamp(chroma(colors.base0F)), + }, syntax) +} + +export const dark = theme(variant) + +export const meta: Meta = variant.meta diff --git a/styles/src/themes/atelier-sulphurpool.ts b/styles/src/themes/atelier-sulphurpool.ts deleted file mode 100644 index e34bc802389a20d7cf6a4cc1cb8dfbff80ed1cd8..0000000000000000000000000000000000000000 --- a/styles/src/themes/atelier-sulphurpool.ts +++ /dev/null @@ -1,45 +0,0 @@ -import chroma from "chroma-js" -import { Meta } from "./common/colorScheme" -import { colorRamp, createColorScheme } from "./common/ramps" - -const name = "Atelier Sulphurpool" - -const ramps = { - neutral: chroma - .scale([ - "#202746", - "#293256", - "#5e6687", - "#6b7394", - "#898ea4", - "#979db4", - "#dfe2f1", - "#f5f7ff", - ]) - .domain([0, 0.2, 0.38, 0.45, 0.65, 0.7, 0.85, 1]), - red: colorRamp(chroma("#c94922")), - orange: colorRamp(chroma("#c76b29")), - yellow: colorRamp(chroma("#c08b30")), - green: colorRamp(chroma("#ac9739")), - cyan: colorRamp(chroma("#22a2c9")), - blue: colorRamp(chroma("#3d8fd1")), - violet: colorRamp(chroma("#6679cc")), - magenta: colorRamp(chroma("#9c637a")), -} - -export const dark = createColorScheme(`${name} Dark`, false, ramps) -export const light = createColorScheme(`${name} Light`, true, ramps) - -export const meta: Meta = { - name, - author: "atelierbram", - license: { - SPDX: "MIT", - license_text: { - https_url: "https://atelierbram.mit-license.org/license.txt", - license_checksum: - "f95ce526ef4e7eecf7a832bba0e3451cc1000f9ce63eb01ed6f64f8109f5d0a5", - } - }, - url: "https://atelierbram.github.io/syntax-highlighting/atelier-schemes/sulphurpool/", -} diff --git a/styles/src/themes/common/atelier-common.ts b/styles/src/themes/common/atelier-common.ts new file mode 100644 index 0000000000000000000000000000000000000000..25dda87c6118c5c8776ec198fb4d1f404c96858c --- /dev/null +++ b/styles/src/themes/common/atelier-common.ts @@ -0,0 +1,66 @@ +import { License, Meta, ThemeSyntax } from "./colorScheme" + +export interface Variant { + meta: Meta + colors: { + base00: string + base01: string + base02: string + base03: string + base04: string + base05: string + base06: string + base07: string + base08: string + base09: string + base0A: string + base0B: string + base0C: string + base0D: string + base0E: string + base0F: string + } +} + +export const metaCommon: { + author: string + license: License +} = { + author: "Bram de Haan (http://atelierbramdehaan.nl)", + license: { + SPDX: "MIT", + license_text: { + https_url: "https://atelierbram.mit-license.org/license.txt", + license_checksum: + "f95ce526ef4e7eecf7a832bba0e3451cc1000f9ce63eb01ed6f64f8109f5d0a5", + } + }, +} + +export const buildSyntax = (variant: Variant): ThemeSyntax => { + const { colors } = variant + return { + primary: { color: colors.base06 }, + comment: { color: colors.base03 }, + "punctuation.delimiter": { color: colors.base05 }, + "punctuation.bracket": { color: colors.base05 }, + "punctuation.special": { color: colors.base0F }, + "string.special.symbol": { color: colors.base0B }, + operator: { color: colors.base05 }, + function: { color: colors.base0D }, + "function.method": { color: colors.base0D }, + "function.special.definition": { color: colors.base0A }, + string: { color: colors.base0B }, + "string.special": { color: colors.base0F }, + "string.regex": { color: colors.base0C }, + type: { color: colors.base0A }, + number: { color: colors.base09 }, + property: { color: colors.base08 }, + variable: { color: colors.base06 }, + "variable.special": { color: colors.base0E }, + variant: { color: colors.base0A }, + keyword: { color: colors.base0E }, + } +} + +export const name = "Atelier" From e0f9b2b40f8fb8f7af16efa0922a4e162ff9824e Mon Sep 17 00:00:00 2001 From: Nate Butler Date: Tue, 7 Mar 2023 13:27:01 -0800 Subject: [PATCH 24/93] Update Atelier Dune --- styles/src/themes/atelier-dune-dark.ts | 55 +++++++++++++++++++++++++ styles/src/themes/atelier-dune-light.ts | 55 +++++++++++++++++++++++++ styles/src/themes/staff/atelier-dune.ts | 35 ---------------- 3 files changed, 110 insertions(+), 35 deletions(-) create mode 100644 styles/src/themes/atelier-dune-dark.ts create mode 100644 styles/src/themes/atelier-dune-light.ts delete mode 100644 styles/src/themes/staff/atelier-dune.ts diff --git a/styles/src/themes/atelier-dune-dark.ts b/styles/src/themes/atelier-dune-dark.ts new file mode 100644 index 0000000000000000000000000000000000000000..a03654339fb71bc955393d3bca5464f4e7e7cd54 --- /dev/null +++ b/styles/src/themes/atelier-dune-dark.ts @@ -0,0 +1,55 @@ +import chroma from "chroma-js" +import { Meta } from "./common/colorScheme" +import { colorRamp, createColorScheme } from "./common/ramps" +import { metaCommon, name, buildSyntax, Variant } from "./common/atelier-common" + +const variant: Variant = { + meta: { + name: `${name} Dune Dark`, + ...metaCommon, + url: "https://atelierbram.github.io/syntax-highlighting/atelier-schemes/cave/", + }, + colors: { + base00: "#20201d", + base01: "#292824", + base02: "#6e6b5e", + base03: "#7d7a68", + base04: "#999580", + base05: "#a6a28c", + base06: "#e8e4cf", + base07: "#fefbec", + base08: "#d73737", + base09: "#b65611", + base0A: "#ae9513", + base0B: "#60ac39", + base0C: "#1fad83", + base0D: "#6684e1", + base0E: "#b854d4", + base0F: "#d43552" + } +} + +const syntax = buildSyntax(variant) + +const theme = (variant: Variant) => { + const { meta, colors } = variant + + return createColorScheme(meta.name, false, { + neutral: chroma + .scale([ + colors.base00, colors.base01, colors.base02, colors.base03, colors.base04, colors.base05, colors.base06, colors.base07 + ]), + red: colorRamp(chroma(colors.base08)), + orange: colorRamp(chroma(colors.base09)), + yellow: colorRamp(chroma(colors.base0A)), + green: colorRamp(chroma(colors.base0B)), + cyan: colorRamp(chroma(colors.base0C)), + blue: colorRamp(chroma(colors.base0D)), + violet: colorRamp(chroma(colors.base0E)), + magenta: colorRamp(chroma(colors.base0F)), + }, syntax) +} + +export const dark = theme(variant) + +export const meta: Meta = variant.meta diff --git a/styles/src/themes/atelier-dune-light.ts b/styles/src/themes/atelier-dune-light.ts new file mode 100644 index 0000000000000000000000000000000000000000..da6a89103ed02b9119751c3bf9ab2f77fe600494 --- /dev/null +++ b/styles/src/themes/atelier-dune-light.ts @@ -0,0 +1,55 @@ +import chroma from "chroma-js" +import { Meta } from "./common/colorScheme" +import { colorRamp, createColorScheme } from "./common/ramps" +import { metaCommon, name, buildSyntax, Variant } from "./common/atelier-common" + +const variant: Variant = { + meta: { + name: `${name} Dune Light`, + ...metaCommon, + url: "https://atelierbram.github.io/syntax-highlighting/atelier-schemes/cave/", + }, + colors: { + base00: "#fefbec", + base01: "#e8e4cf", + base02: "#a6a28c", + base03: "#999580", + base04: "#7d7a68", + base05: "#6e6b5e", + base06: "#292824", + base07: "#20201d", + base08: "#d73737", + base09: "#b65611", + base0A: "#ae9513", + base0B: "#60ac39", + base0C: "#1fad83", + base0D: "#6684e1", + base0E: "#b854d4", + base0F: "#d43552" + } +} + +const syntax = buildSyntax(variant) + +const theme = (variant: Variant) => { + const { meta, colors } = variant + + return createColorScheme(meta.name, true, { + neutral: chroma + .scale([ + colors.base00, colors.base01, colors.base02, colors.base03, colors.base04, colors.base05, colors.base06, colors.base07 + ].reverse()), + red: colorRamp(chroma(colors.base08)), + orange: colorRamp(chroma(colors.base09)), + yellow: colorRamp(chroma(colors.base0A)), + green: colorRamp(chroma(colors.base0B)), + cyan: colorRamp(chroma(colors.base0C)), + blue: colorRamp(chroma(colors.base0D)), + violet: colorRamp(chroma(colors.base0E)), + magenta: colorRamp(chroma(colors.base0F)), + }, syntax) +} + +export const dark = theme(variant) + +export const meta: Meta = variant.meta diff --git a/styles/src/themes/staff/atelier-dune.ts b/styles/src/themes/staff/atelier-dune.ts deleted file mode 100644 index bd39098dc3575ce8a0a4c515e6a33d151a521658..0000000000000000000000000000000000000000 --- a/styles/src/themes/staff/atelier-dune.ts +++ /dev/null @@ -1,35 +0,0 @@ -import chroma from "chroma-js" -import { colorRamp, createColorScheme } from "../common/ramps" - -const name = "Atelier Dune" -const author = "atelierbram" -const url = - "https://atelierbram.github.io/syntax-highlighting/atelier-schemes/dune/" -const license = { - type: "MIT", - url: "https://github.com/atelierbram/syntax-highlighting/blob/master/LICENSE", -} - -const ramps = { - neutral: chroma.scale([ - "#20201d", - "#292824", - "#6e6b5e", - "#7d7a68", - "#999580", - "#a6a28c", - "#e8e4cf", - "#fefbec", - ]), - red: colorRamp(chroma("#d73737")), - orange: colorRamp(chroma("#b65611")), - yellow: colorRamp(chroma("#ae9513")), - green: colorRamp(chroma("#60ac39")), - cyan: colorRamp(chroma("#1fad83")), - blue: colorRamp(chroma("#6684e1")), - violet: colorRamp(chroma("#b854d4")), - magenta: colorRamp(chroma("#d43552")), -} - -export const dark = createColorScheme(`${name} Dark`, false, ramps) -export const light = createColorScheme(`${name} Light`, true, ramps) From 90296667b0b3c20d5374bc7ba6badeec939bedd8 Mon Sep 17 00:00:00 2001 From: Nate Butler Date: Tue, 7 Mar 2023 13:35:23 -0800 Subject: [PATCH 25/93] Remove current staff themes --- styles/src/themes/staff/abruzzo.ts | 31 --------- styles/src/themes/staff/atelier-heath.ts | 54 --------------- styles/src/themes/staff/atelier-seaside.ts | 35 ---------- styles/src/themes/staff/ayu-mirage.ts | 31 --------- styles/src/themes/staff/ayu.ts | 52 -------------- styles/src/themes/staff/brushtrees.ts | 73 -------------------- styles/src/themes/staff/dracula.ts | 31 --------- styles/src/themes/staff/monokai.ts | 32 --------- styles/src/themes/staff/nord.ts | 32 --------- styles/src/themes/staff/seti-ui.ts | 32 --------- styles/src/themes/staff/tokyo-night-storm.ts | 32 --------- styles/src/themes/staff/tokyo-night.ts | 53 -------------- styles/src/themes/staff/zenburn.ts | 31 --------- 13 files changed, 519 deletions(-) delete mode 100644 styles/src/themes/staff/abruzzo.ts delete mode 100644 styles/src/themes/staff/atelier-heath.ts delete mode 100644 styles/src/themes/staff/atelier-seaside.ts delete mode 100644 styles/src/themes/staff/ayu-mirage.ts delete mode 100644 styles/src/themes/staff/ayu.ts delete mode 100644 styles/src/themes/staff/brushtrees.ts delete mode 100644 styles/src/themes/staff/dracula.ts delete mode 100644 styles/src/themes/staff/monokai.ts delete mode 100644 styles/src/themes/staff/nord.ts delete mode 100644 styles/src/themes/staff/seti-ui.ts delete mode 100644 styles/src/themes/staff/tokyo-night-storm.ts delete mode 100644 styles/src/themes/staff/tokyo-night.ts delete mode 100644 styles/src/themes/staff/zenburn.ts diff --git a/styles/src/themes/staff/abruzzo.ts b/styles/src/themes/staff/abruzzo.ts deleted file mode 100644 index 43b75f26133c2aeca4d1e4c1369f31ee25a0358b..0000000000000000000000000000000000000000 --- a/styles/src/themes/staff/abruzzo.ts +++ /dev/null @@ -1,31 +0,0 @@ -import chroma from "chroma-js" -import { colorRamp, createColorScheme } from "../common/ramps" - -const name = "Abruzzo" -const author = "slightknack " -const url = "https://github.com/slightknack" -const license = { - type: "", - url: "", -} - -export const dark = createColorScheme(name, false, { - neutral: chroma.scale([ - "#1b0d05", - "#2c1e18", - "#654035", - "#9d5e4a", - "#b37354", - "#c1825a", - "#dda66e", - "#fbf3e2", - ]), - red: colorRamp(chroma("#e594c4")), - orange: colorRamp(chroma("#d9e87e")), - yellow: colorRamp(chroma("#fd9d83")), - green: colorRamp(chroma("#96adf7")), - cyan: colorRamp(chroma("#fc798f")), - blue: colorRamp(chroma("#BCD0F5")), - violet: colorRamp(chroma("#dac5eb")), - magenta: colorRamp(chroma("#c1a3ef")), -}) diff --git a/styles/src/themes/staff/atelier-heath.ts b/styles/src/themes/staff/atelier-heath.ts deleted file mode 100644 index cd4eb2a1ac597c127b384c6f83f478c78737ed4d..0000000000000000000000000000000000000000 --- a/styles/src/themes/staff/atelier-heath.ts +++ /dev/null @@ -1,54 +0,0 @@ -import chroma from "chroma-js" -import { colorRamp, createColorScheme } from "../common/ramps" - -const name = "Atelier Heath" -const author = "atelierbram" -const url = - "https://atelierbram.github.io/syntax-highlighting/atelier-schemes/heath/" -const license = { - type: "MIT", - url: "https://github.com/atelierbram/syntax-highlighting/blob/master/LICENSE", -} - -// `name-[light|dark]`, isLight, color ramps -export const dark = createColorScheme(`${name} Dark`, false, { - neutral: chroma.scale([ - "#1b181b", - "#292329", - "#695d69", - "#776977", - "#9e8f9e", - "#ab9bab", - "#d8cad8", - "#f7f3f7", - ]), - red: colorRamp(chroma("#ca402b")), - orange: colorRamp(chroma("#a65926")), - yellow: colorRamp(chroma("#bb8a35")), - green: colorRamp(chroma("#918b3b")), - cyan: colorRamp(chroma("#159393")), - blue: colorRamp(chroma("#516aec")), - violet: colorRamp(chroma("#7b59c0")), - magenta: colorRamp(chroma("#cc33cc")), -}) - -export const light = createColorScheme(`${name} Light`, true, { - neutral: chroma.scale([ - "#161b1d", - "#1f292e", - "#516d7b", - "#5a7b8c", - "#7195a8", - "#7ea2b4", - "#c1e4f6", - "#ebf8ff", - ]), - red: colorRamp(chroma("#d22d72")), - orange: colorRamp(chroma("#935c25")), - yellow: colorRamp(chroma("#8a8a0f")), - green: colorRamp(chroma("#568c3b")), - cyan: colorRamp(chroma("#2d8f6f")), - blue: colorRamp(chroma("#257fad")), - violet: colorRamp(chroma("#6b6bb8")), - magenta: colorRamp(chroma("#b72dd2")), -}) diff --git a/styles/src/themes/staff/atelier-seaside.ts b/styles/src/themes/staff/atelier-seaside.ts deleted file mode 100644 index 13286e77f929b11ebce5c0a5405f505d9ee34669..0000000000000000000000000000000000000000 --- a/styles/src/themes/staff/atelier-seaside.ts +++ /dev/null @@ -1,35 +0,0 @@ -import chroma from "chroma-js" -import { colorRamp, createColorScheme } from "../common/ramps" - -const name = "Atelier Seaside" -const author = "atelierbram" -const url = - "https://atelierbram.github.io/syntax-highlighting/atelier-schemes/seaside/" -const license = { - type: "MIT", - url: "https://github.com/atelierbram/syntax-highlighting/blob/master/LICENSE", -} - -const ramps = { - neutral: chroma.scale([ - "#131513", - "#242924", - "#5e6e5e", - "#687d68", - "#809980", - "#8ca68c", - "#cfe8cf", - "#f4fbf4", - ]), - red: colorRamp(chroma("#e6193c")), - orange: colorRamp(chroma("#87711d")), - yellow: colorRamp(chroma("#98981b")), - green: colorRamp(chroma("#29a329")), - cyan: colorRamp(chroma("#1999b3")), - blue: colorRamp(chroma("#3d62f5")), - violet: colorRamp(chroma("#ad2bee")), - magenta: colorRamp(chroma("#e619c3")), -} - -export const dark = createColorScheme(`${name} Dark`, false, ramps) -export const light = createColorScheme(`${name} Light`, true, ramps) diff --git a/styles/src/themes/staff/ayu-mirage.ts b/styles/src/themes/staff/ayu-mirage.ts deleted file mode 100644 index 5b832699b46b984d9fd0fdaff223073613095aed..0000000000000000000000000000000000000000 --- a/styles/src/themes/staff/ayu-mirage.ts +++ /dev/null @@ -1,31 +0,0 @@ -import chroma from "chroma-js" -import { colorRamp, createColorScheme } from "../common/ramps" - -const name = "Ayu" -const author = "Konstantin Pschera " -const url = "https://github.com/ayu-theme/ayu-colors" -const license = { - type: "MIT", - url: "https://github.com/ayu-theme/ayu-colors/blob/master/license", -} - -export const dark = createColorScheme(`${name} Mirage`, false, { - neutral: chroma.scale([ - "#171B24", - "#1F2430", - "#242936", - "#707A8C", - "#8A9199", - "#CCCAC2", - "#D9D7CE", - "#F3F4F5", - ]), - red: colorRamp(chroma("#F28779")), - orange: colorRamp(chroma("#FFAD66")), - yellow: colorRamp(chroma("#FFD173")), - green: colorRamp(chroma("#D5FF80")), - cyan: colorRamp(chroma("#95E6CB")), - blue: colorRamp(chroma("#5CCFE6")), - violet: colorRamp(chroma("#D4BFFF")), - magenta: colorRamp(chroma("#F29E74")), -}) diff --git a/styles/src/themes/staff/ayu.ts b/styles/src/themes/staff/ayu.ts deleted file mode 100644 index 24fcdb951b07aa3e7346c28566b26a549e388928..0000000000000000000000000000000000000000 --- a/styles/src/themes/staff/ayu.ts +++ /dev/null @@ -1,52 +0,0 @@ -import chroma from "chroma-js" -import { colorRamp, createColorScheme } from "../common/ramps" - -const name = "Ayu" -const author = "Konstantin Pschera " -const url = "https://github.com/ayu-theme/ayu-colors" -const license = { - type: "MIT", - url: "https://github.com/ayu-theme/ayu-colors/blob/master/license", -} - -export const dark = createColorScheme(`${name} Dark`, false, { - neutral: chroma.scale([ - "#0F1419", - "#131721", - "#272D38", - "#3E4B59", - "#BFBDB6", - "#E6E1CF", - "#E6E1CF", - "#F3F4F5", - ]), - red: colorRamp(chroma("#F07178")), - orange: colorRamp(chroma("#FF8F40")), - yellow: colorRamp(chroma("#FFB454")), - green: colorRamp(chroma("#B8CC52")), - cyan: colorRamp(chroma("#95E6CB")), - blue: colorRamp(chroma("#59C2FF")), - violet: colorRamp(chroma("#D2A6FF")), - magenta: colorRamp(chroma("#E6B673")), -}) - -export const light = createColorScheme(`${name} Light`, true, { - neutral: chroma.scale([ - "#1A1F29", - "#242936", - "#5C6773", - "#828C99", - "#ABB0B6", - "#F8F9FA", - "#F3F4F5", - "#FAFAFA", - ]), - red: colorRamp(chroma("#F07178")), - orange: colorRamp(chroma("#FA8D3E")), - yellow: colorRamp(chroma("#F2AE49")), - green: colorRamp(chroma("#86B300")), - cyan: colorRamp(chroma("#4CBF99")), - blue: colorRamp(chroma("#36A3D9")), - violet: colorRamp(chroma("#A37ACC")), - magenta: colorRamp(chroma("#E6BA7E")), -}) diff --git a/styles/src/themes/staff/brushtrees.ts b/styles/src/themes/staff/brushtrees.ts deleted file mode 100644 index a17cf92acb563b4ceea672f79436566062c86db8..0000000000000000000000000000000000000000 --- a/styles/src/themes/staff/brushtrees.ts +++ /dev/null @@ -1,73 +0,0 @@ -import chroma from "chroma-js" -import { colorRamp, createColorScheme } from "../common/ramps" - -const name = "Brush Trees" -const author = "Abraham White " -const url = "https://github.com/WhiteAbeLincoln/base16-brushtrees-scheme" -const license = { - type: "MIT", - url: "https://github.com/WhiteAbeLincoln/base16-brushtrees-scheme/blob/master/LICENSE", -} - -export const dark = createColorScheme(`${name} Dark`, false, { - neutral: chroma.scale([ - "#485867", - "#5A6D7A", - "#6D828E", - "#8299A1", - "#98AFB5", - "#B0C5C8", - "#C9DBDC", - "#E3EFEF", - ]), - red: colorRamp(chroma("#b38686")), - orange: colorRamp(chroma("#d8bba2")), - yellow: colorRamp(chroma("#aab386")), - green: colorRamp(chroma("#87b386")), - cyan: colorRamp(chroma("#86b3b3")), - blue: colorRamp(chroma("#868cb3")), - violet: colorRamp(chroma("#b386b2")), - magenta: colorRamp(chroma("#b39f9f")), -}) - -export const mirage = createColorScheme(`${name} Mirage`, false, { - neutral: chroma.scale([ - "#485867", - "#5A6D7A", - "#6D828E", - "#8299A1", - "#98AFB5", - "#B0C5C8", - "#C9DBDC", - "#E3EFEF", - ]), - red: colorRamp(chroma("#F28779")), - orange: colorRamp(chroma("#FFAD66")), - yellow: colorRamp(chroma("#FFD173")), - green: colorRamp(chroma("#D5FF80")), - cyan: colorRamp(chroma("#95E6CB")), - blue: colorRamp(chroma("#5CCFE6")), - violet: colorRamp(chroma("#D4BFFF")), - magenta: colorRamp(chroma("#F29E74")), -}) - -export const light = createColorScheme(`${name} Light`, true, { - neutral: chroma.scale([ - "#1A1F29", - "#242936", - "#5C6773", - "#828C99", - "#ABB0B6", - "#F8F9FA", - "#F3F4F5", - "#FAFAFA", - ]), - red: colorRamp(chroma("#b38686")), - orange: colorRamp(chroma("#d8bba2")), - yellow: colorRamp(chroma("#aab386")), - green: colorRamp(chroma("#87b386")), - cyan: colorRamp(chroma("#86b3b3")), - blue: colorRamp(chroma("#868cb3")), - violet: colorRamp(chroma("#b386b2")), - magenta: colorRamp(chroma("#b39f9f")), -}) diff --git a/styles/src/themes/staff/dracula.ts b/styles/src/themes/staff/dracula.ts deleted file mode 100644 index acff08d230378eae13522712a8b74419a33edf05..0000000000000000000000000000000000000000 --- a/styles/src/themes/staff/dracula.ts +++ /dev/null @@ -1,31 +0,0 @@ -import chroma from "chroma-js" -import { colorRamp, createColorScheme } from "../common/ramps" - -const name = "Dracula" -const author = "zenorocha" -const url = "https://github.com/dracula/dracula-theme" -const license = { - type: "MIT", - url: "https://github.com/dracula/dracula-theme/blob/master/LICENSE", -} - -export const dark = createColorScheme(name, false, { - neutral: chroma.scale([ - "#282A36", - "#3a3c4e", - "#4d4f68", - "#626483", - "#62d6e8", - "#e9e9f4", - "#f1f2f8", - "#f8f8f2", - ]), - red: colorRamp(chroma("#ff5555")), - orange: colorRamp(chroma("#ffb86c")), - yellow: colorRamp(chroma("#f1fa8c")), - green: colorRamp(chroma("#50fa7b")), - cyan: colorRamp(chroma("#8be9fd")), - blue: colorRamp(chroma("#6272a4")), - violet: colorRamp(chroma("#bd93f9")), - magenta: colorRamp(chroma("#00f769")), -}) diff --git a/styles/src/themes/staff/monokai.ts b/styles/src/themes/staff/monokai.ts deleted file mode 100644 index 75319e527a7d088721083e0e639e1ba66bc636cc..0000000000000000000000000000000000000000 --- a/styles/src/themes/staff/monokai.ts +++ /dev/null @@ -1,32 +0,0 @@ -import chroma from "chroma-js" -import { colorRamp, createColorScheme } from "../common/ramps" - -const name = "Monokai" -const author = "Wimer Hazenberg (http://www.monokai.nl)" -const url = "https://base16.netlify.app/previews/base16-monokai.html" -const license = { - type: "?", - url: "?", -} - -// `name-[light|dark]`, isLight, color ramps -export const dark = createColorScheme(name, false, { - neutral: chroma.scale([ - "#272822", - "#383830", - "#49483e", - "#75715e", - "#a59f85", - "#f8f8f2", - "#f5f4f1", - "#f9f8f5", - ]), - red: colorRamp(chroma("#f92672")), - orange: colorRamp(chroma("#fd971f")), - yellow: colorRamp(chroma("#f4bf75")), - green: colorRamp(chroma("#a6e22e")), - cyan: colorRamp(chroma("#a1efe4")), - blue: colorRamp(chroma("#66d9ef")), - violet: colorRamp(chroma("#ae81ff")), - magenta: colorRamp(chroma("#cc6633")), -}) diff --git a/styles/src/themes/staff/nord.ts b/styles/src/themes/staff/nord.ts deleted file mode 100644 index 48f924e7a403cb5118ea96797afca75b703ef152..0000000000000000000000000000000000000000 --- a/styles/src/themes/staff/nord.ts +++ /dev/null @@ -1,32 +0,0 @@ -import chroma from "chroma-js" -import { colorRamp, createColorScheme } from "../common/ramps" - -const name = "Nord" -const author = "arcticicestudio" -const url = "https://www.nordtheme.com/" -const license = { - type: "MIT", - url: "https://github.com/arcticicestudio/nord/blob/develop/LICENSE.md", -} - -// `name-[light|dark]`, isLight, color ramps -export const dark = createColorScheme(name, false, { - neutral: chroma.scale([ - "#2E3440", - "#3B4252", - "#434C5E", - "#4C566A", - "#D8DEE9", - "#E5E9F0", - "#ECEFF4", - "#8FBCBB", - ]), - red: colorRamp(chroma("#88C0D0")), - orange: colorRamp(chroma("#81A1C1")), - yellow: colorRamp(chroma("#5E81AC")), - green: colorRamp(chroma("#BF616A")), - cyan: colorRamp(chroma("#D08770")), - blue: colorRamp(chroma("#EBCB8B")), - violet: colorRamp(chroma("#A3BE8C")), - magenta: colorRamp(chroma("#B48EAD")), -}) diff --git a/styles/src/themes/staff/seti-ui.ts b/styles/src/themes/staff/seti-ui.ts deleted file mode 100644 index abf6624242ce48373a5675a717cf217ec0fdd360..0000000000000000000000000000000000000000 --- a/styles/src/themes/staff/seti-ui.ts +++ /dev/null @@ -1,32 +0,0 @@ -import chroma from "chroma-js" -import { colorRamp, createColorScheme } from "../common/ramps" - -const name = "Seti UI" -const author = "jesseweed" -const url = "https://github.com/jesseweed/seti-ui" -const license = { - type: "MIT", - url: "https://github.com/jesseweed/seti-ui/blob/master/LICENSE.md", -} - -// `name-[light|dark]`, isLight, color ramps -export const dark = createColorScheme(name, false, { - neutral: chroma.scale([ - "#151718", - "#262B30", - "#1E2326", - "#41535B", - "#43a5d5", - "#d6d6d6", - "#eeeeee", - "#ffffff", - ]), - red: colorRamp(chroma("#Cd3f45")), - orange: colorRamp(chroma("#db7b55")), - yellow: colorRamp(chroma("#e6cd69")), - green: colorRamp(chroma("#9fca56")), - cyan: colorRamp(chroma("#55dbbe")), - blue: colorRamp(chroma("#55b5db")), - violet: colorRamp(chroma("#a074c4")), - magenta: colorRamp(chroma("#8a553f")), -}) diff --git a/styles/src/themes/staff/tokyo-night-storm.ts b/styles/src/themes/staff/tokyo-night-storm.ts deleted file mode 100644 index 399c5268721c05e3696a8881e5eb97e0967e83fe..0000000000000000000000000000000000000000 --- a/styles/src/themes/staff/tokyo-night-storm.ts +++ /dev/null @@ -1,32 +0,0 @@ -import chroma from "chroma-js" -import { colorRamp, createColorScheme } from "../common/ramps" - -const name = "Tokyo Night Storm" -const author = "folke" -const url = "https://github.com/folke/tokyonight.nvim" -const license = { - type: "MIT", - url: "https://github.com/ghifarit53/tokyonight-vim/blob/master/LICENSE", -} - -// `name-[light|dark]`, isLight, color ramps -export const dark = createColorScheme(name, false, { - neutral: chroma.scale([ - "#24283B", - "#16161E", - "#343A52", - "#444B6A", - "#787C99", - "#A9B1D6", - "#CBCCD1", - "#D5D6DB", - ]), - red: colorRamp(chroma("#C0CAF5")), - orange: colorRamp(chroma("#A9B1D6")), - yellow: colorRamp(chroma("#0DB9D7")), - green: colorRamp(chroma("#9ECE6A")), - cyan: colorRamp(chroma("#B4F9F8")), - blue: colorRamp(chroma("#2AC3DE")), - violet: colorRamp(chroma("#BB9AF7")), - magenta: colorRamp(chroma("#F7768E")), -}) diff --git a/styles/src/themes/staff/tokyo-night.ts b/styles/src/themes/staff/tokyo-night.ts deleted file mode 100644 index 267b1fc031b311e3a57c479c9978041f9b7cbbeb..0000000000000000000000000000000000000000 --- a/styles/src/themes/staff/tokyo-night.ts +++ /dev/null @@ -1,53 +0,0 @@ -import chroma from "chroma-js" -import { colorRamp, createColorScheme } from "../common/ramps" - -const name = "Tokyo" -const author = "folke" -const url = "https://github.com/folke/tokyonight.nvim" -const license = { - type: "Apache License 2.0", - url: "https://github.com/folke/tokyonight.nvim/blob/main/LICENSE", -} - -// `name-[light|dark]`, isLight, color ramps -export const dark = createColorScheme(`${name} Night`, false, { - neutral: chroma.scale([ - "#1A1B26", - "#16161E", - "#2F3549", - "#444B6A", - "#787C99", - "#A9B1D6", - "#CBCCD1", - "#D5D6DB", - ]), - red: colorRamp(chroma("#C0CAF5")), - orange: colorRamp(chroma("#A9B1D6")), - yellow: colorRamp(chroma("#0DB9D7")), - green: colorRamp(chroma("#9ECE6A")), - cyan: colorRamp(chroma("#B4F9F8")), - blue: colorRamp(chroma("#2AC3DE")), - violet: colorRamp(chroma("#BB9AF7")), - magenta: colorRamp(chroma("#F7768E")), -}) - -export const light = createColorScheme(`${name} Day`, true, { - neutral: chroma.scale([ - "#1A1B26", - "#1A1B26", - "#343B59", - "#4C505E", - "#9699A3", - "#DFE0E5", - "#CBCCD1", - "#D5D6DB", - ]), - red: colorRamp(chroma("#343B58")), - orange: colorRamp(chroma("#965027")), - yellow: colorRamp(chroma("#166775")), - green: colorRamp(chroma("#485E30")), - cyan: colorRamp(chroma("#3E6968")), - blue: colorRamp(chroma("#34548A")), - violet: colorRamp(chroma("#5A4A78")), - magenta: colorRamp(chroma("#8C4351")), -}) diff --git a/styles/src/themes/staff/zenburn.ts b/styles/src/themes/staff/zenburn.ts deleted file mode 100644 index 9457ef195795188d5f467a9d74dde441eec208b6..0000000000000000000000000000000000000000 --- a/styles/src/themes/staff/zenburn.ts +++ /dev/null @@ -1,31 +0,0 @@ -import chroma from "chroma-js" -import { colorRamp, createColorScheme } from "../common/ramps" - -const name = "Zenburn" -const author = "elnawe" -const url = "https://github.com/elnawe/base16-zenburn-scheme" -const license = { - type: "None", - url: "", -} - -export const dark = createColorScheme(name, false, { - neutral: chroma.scale([ - "#383838", - "#404040", - "#606060", - "#6f6f6f", - "#808080", - "#dcdccc", - "#c0c0c0", - "#ffffff", - ]), - red: colorRamp(chroma("#dca3a3")), - orange: colorRamp(chroma("#dfaf8f")), - yellow: colorRamp(chroma("#e0cf9f")), - green: colorRamp(chroma("#5f7f5f")), - cyan: colorRamp(chroma("#93e0e3")), - blue: colorRamp(chroma("#7cb8bb")), - violet: colorRamp(chroma("#dc8cc3")), - magenta: colorRamp(chroma("#000000")), -}) From 4e81513af15918cd42f8c674c4b729a9d154eac8 Mon Sep 17 00:00:00 2001 From: Nate Butler Date: Tue, 7 Mar 2023 13:35:32 -0800 Subject: [PATCH 26/93] Add more Atelier themes --- styles/src/themes/atelier-dune-dark.ts | 2 +- styles/src/themes/atelier-dune-light.ts | 2 +- styles/src/themes/atelier-estuary-dark.ts | 55 ++++++++++++++++++++++ styles/src/themes/atelier-estuary-light.ts | 55 ++++++++++++++++++++++ 4 files changed, 112 insertions(+), 2 deletions(-) create mode 100644 styles/src/themes/atelier-estuary-dark.ts create mode 100644 styles/src/themes/atelier-estuary-light.ts diff --git a/styles/src/themes/atelier-dune-dark.ts b/styles/src/themes/atelier-dune-dark.ts index a03654339fb71bc955393d3bca5464f4e7e7cd54..b6f90b4c4485130e112a00597524339bc94830d8 100644 --- a/styles/src/themes/atelier-dune-dark.ts +++ b/styles/src/themes/atelier-dune-dark.ts @@ -7,7 +7,7 @@ const variant: Variant = { meta: { name: `${name} Dune Dark`, ...metaCommon, - url: "https://atelierbram.github.io/syntax-highlighting/atelier-schemes/cave/", + url: "https://atelierbram.github.io/syntax-highlighting/atelier-schemes/dune/", }, colors: { base00: "#20201d", diff --git a/styles/src/themes/atelier-dune-light.ts b/styles/src/themes/atelier-dune-light.ts index da6a89103ed02b9119751c3bf9ab2f77fe600494..0a95dc66fc9c9432a5601b9cb2a3c8b0ea9a2a59 100644 --- a/styles/src/themes/atelier-dune-light.ts +++ b/styles/src/themes/atelier-dune-light.ts @@ -7,7 +7,7 @@ const variant: Variant = { meta: { name: `${name} Dune Light`, ...metaCommon, - url: "https://atelierbram.github.io/syntax-highlighting/atelier-schemes/cave/", + url: "https://atelierbram.github.io/syntax-highlighting/atelier-schemes/dune/", }, colors: { base00: "#fefbec", diff --git a/styles/src/themes/atelier-estuary-dark.ts b/styles/src/themes/atelier-estuary-dark.ts new file mode 100644 index 0000000000000000000000000000000000000000..94ca7aa63bafda4438f7d672721eaae82a0e1ae2 --- /dev/null +++ b/styles/src/themes/atelier-estuary-dark.ts @@ -0,0 +1,55 @@ +import chroma from "chroma-js" +import { Meta } from "./common/colorScheme" +import { colorRamp, createColorScheme } from "./common/ramps" +import { metaCommon, name, buildSyntax, Variant } from "./common/atelier-common" + +const variant: Variant = { + meta: { + name: `${name} Estuary Dark`, + ...metaCommon, + url: "https://atelierbram.github.io/syntax-highlighting/atelier-schemes/estuary/", + }, + colors: { + base00: "#22221b", + base01: "#302f27", + base02: "#5f5e4e", + base03: "#6c6b5a", + base04: "#878573", + base05: "#929181", + base06: "#e7e6df", + base07: "#f4f3ec", + base08: "#ba6236", + base09: "#ae7313", + base0A: "#a5980d", + base0B: "#7d9726", + base0C: "#5b9d48", + base0D: "#36a166", + base0E: "#5f9182", + base0F: "#9d6c7c" + } +} + +const syntax = buildSyntax(variant) + +const theme = (variant: Variant) => { + const { meta, colors } = variant + + return createColorScheme(meta.name, false, { + neutral: chroma + .scale([ + colors.base00, colors.base01, colors.base02, colors.base03, colors.base04, colors.base05, colors.base06, colors.base07 + ]), + red: colorRamp(chroma(colors.base08)), + orange: colorRamp(chroma(colors.base09)), + yellow: colorRamp(chroma(colors.base0A)), + green: colorRamp(chroma(colors.base0B)), + cyan: colorRamp(chroma(colors.base0C)), + blue: colorRamp(chroma(colors.base0D)), + violet: colorRamp(chroma(colors.base0E)), + magenta: colorRamp(chroma(colors.base0F)), + }, syntax) +} + +export const dark = theme(variant) + +export const meta: Meta = variant.meta diff --git a/styles/src/themes/atelier-estuary-light.ts b/styles/src/themes/atelier-estuary-light.ts new file mode 100644 index 0000000000000000000000000000000000000000..4dd4b875498aca4e35716fb032a2bfd391a1fbda --- /dev/null +++ b/styles/src/themes/atelier-estuary-light.ts @@ -0,0 +1,55 @@ +import chroma from "chroma-js" +import { Meta } from "./common/colorScheme" +import { colorRamp, createColorScheme } from "./common/ramps" +import { metaCommon, name, buildSyntax, Variant } from "./common/atelier-common" + +const variant: Variant = { + meta: { + name: `${name} Estuary Light`, + ...metaCommon, + url: "https://atelierbram.github.io/syntax-highlighting/atelier-schemes/estuary/", + }, + colors: { + base00: "#f4f3ec", + base01: "#e7e6df", + base02: "#929181", + base03: "#878573", + base04: "#6c6b5a", + base05: "#5f5e4e", + base06: "#302f27", + base07: "#22221b", + base08: "#ba6236", + base09: "#ae7313", + base0A: "#a5980d", + base0B: "#7d9726", + base0C: "#5b9d48", + base0D: "#36a166", + base0E: "#5f9182", + base0F: "#9d6c7c" + } +} + +const syntax = buildSyntax(variant) + +const theme = (variant: Variant) => { + const { meta, colors } = variant + + return createColorScheme(meta.name, true, { + neutral: chroma + .scale([ + colors.base00, colors.base01, colors.base02, colors.base03, colors.base04, colors.base05, colors.base06, colors.base07 + ].reverse()), + red: colorRamp(chroma(colors.base08)), + orange: colorRamp(chroma(colors.base09)), + yellow: colorRamp(chroma(colors.base0A)), + green: colorRamp(chroma(colors.base0B)), + cyan: colorRamp(chroma(colors.base0C)), + blue: colorRamp(chroma(colors.base0D)), + violet: colorRamp(chroma(colors.base0E)), + magenta: colorRamp(chroma(colors.base0F)), + }, syntax) +} + +export const dark = theme(variant) + +export const meta: Meta = variant.meta From 84aefb9dcb763836dc79228e8e553a65a9cd7666 Mon Sep 17 00:00:00 2001 From: Nate Butler Date: Tue, 7 Mar 2023 13:47:18 -0800 Subject: [PATCH 27/93] Add the rest of the Atelier dark themes --- styles/src/themes/atelier-forest-dark.ts | 55 ++++++++++++++++++++++ styles/src/themes/atelier-heath-dark.ts | 55 ++++++++++++++++++++++ styles/src/themes/atelier-lakeside-dark.ts | 55 ++++++++++++++++++++++ styles/src/themes/atelier-plateau-dark.ts | 55 ++++++++++++++++++++++ styles/src/themes/atelier-savanna-dark.ts | 55 ++++++++++++++++++++++ styles/src/themes/atelier-seaside-dark.ts | 55 ++++++++++++++++++++++ 6 files changed, 330 insertions(+) create mode 100644 styles/src/themes/atelier-forest-dark.ts create mode 100644 styles/src/themes/atelier-heath-dark.ts create mode 100644 styles/src/themes/atelier-lakeside-dark.ts create mode 100644 styles/src/themes/atelier-plateau-dark.ts create mode 100644 styles/src/themes/atelier-savanna-dark.ts create mode 100644 styles/src/themes/atelier-seaside-dark.ts diff --git a/styles/src/themes/atelier-forest-dark.ts b/styles/src/themes/atelier-forest-dark.ts new file mode 100644 index 0000000000000000000000000000000000000000..2bfe285a165497528288a60877fedef252f0023b --- /dev/null +++ b/styles/src/themes/atelier-forest-dark.ts @@ -0,0 +1,55 @@ +import chroma from "chroma-js" +import { Meta } from "./common/colorScheme" +import { colorRamp, createColorScheme } from "./common/ramps" +import { metaCommon, name, buildSyntax, Variant } from "./common/atelier-common" + +const variant: Variant = { + meta: { + name: `${name} Forest Dark`, + ...metaCommon, + url: "https://atelierbram.github.io/syntax-highlighting/atelier-schemes/forest/", + }, + colors: { + base00: "#1b1918", + base01: "#2c2421", + base02: "#68615e", + base03: "#766e6b", + base04: "#9c9491", + base05: "#a8a19f", + base06: "#e6e2e0", + base07: "#f1efee", + base08: "#f22c40", + base09: "#df5320", + base0A: "#c38418", + base0B: "#7b9726", + base0C: "#3d97b8", + base0D: "#407ee7", + base0E: "#6666ea", + base0F: "#c33ff3" + } +} + +const syntax = buildSyntax(variant) + +const theme = (variant: Variant) => { + const { meta, colors } = variant + + return createColorScheme(meta.name, false, { + neutral: chroma + .scale([ + colors.base00, colors.base01, colors.base02, colors.base03, colors.base04, colors.base05, colors.base06, colors.base07 + ]), + red: colorRamp(chroma(colors.base08)), + orange: colorRamp(chroma(colors.base09)), + yellow: colorRamp(chroma(colors.base0A)), + green: colorRamp(chroma(colors.base0B)), + cyan: colorRamp(chroma(colors.base0C)), + blue: colorRamp(chroma(colors.base0D)), + violet: colorRamp(chroma(colors.base0E)), + magenta: colorRamp(chroma(colors.base0F)), + }, syntax) +} + +export const dark = theme(variant) + +export const meta: Meta = variant.meta diff --git a/styles/src/themes/atelier-heath-dark.ts b/styles/src/themes/atelier-heath-dark.ts new file mode 100644 index 0000000000000000000000000000000000000000..9ae14a8903f1d74bc1befbc0c5476c87308e2ebc --- /dev/null +++ b/styles/src/themes/atelier-heath-dark.ts @@ -0,0 +1,55 @@ +import chroma from "chroma-js" +import { Meta } from "./common/colorScheme" +import { colorRamp, createColorScheme } from "./common/ramps" +import { metaCommon, name, buildSyntax, Variant } from "./common/atelier-common" + +const variant: Variant = { + meta: { + name: `${name} Heath Dark`, + ...metaCommon, + url: "https://atelierbram.github.io/syntax-highlighting/atelier-schemes/heath/", + }, + colors: { + base00: "#1b181b", + base01: "#292329", + base02: "#695d69", + base03: "#776977", + base04: "#9e8f9e", + base05: "#ab9bab", + base06: "#d8cad8", + base07: "#f7f3f7", + base08: "#ca402b", + base09: "#a65926", + base0A: "#bb8a35", + base0B: "#918b3b", + base0C: "#159393", + base0D: "#516aec", + base0E: "#7b59c0", + base0F: "#cc33cc" + } +} + +const syntax = buildSyntax(variant) + +const theme = (variant: Variant) => { + const { meta, colors } = variant + + return createColorScheme(meta.name, false, { + neutral: chroma + .scale([ + colors.base00, colors.base01, colors.base02, colors.base03, colors.base04, colors.base05, colors.base06, colors.base07 + ]), + red: colorRamp(chroma(colors.base08)), + orange: colorRamp(chroma(colors.base09)), + yellow: colorRamp(chroma(colors.base0A)), + green: colorRamp(chroma(colors.base0B)), + cyan: colorRamp(chroma(colors.base0C)), + blue: colorRamp(chroma(colors.base0D)), + violet: colorRamp(chroma(colors.base0E)), + magenta: colorRamp(chroma(colors.base0F)), + }, syntax) +} + +export const dark = theme(variant) + +export const meta: Meta = variant.meta diff --git a/styles/src/themes/atelier-lakeside-dark.ts b/styles/src/themes/atelier-lakeside-dark.ts new file mode 100644 index 0000000000000000000000000000000000000000..45f5733cf9326c42ee2884f15086a9ba639bb6d2 --- /dev/null +++ b/styles/src/themes/atelier-lakeside-dark.ts @@ -0,0 +1,55 @@ +import chroma from "chroma-js" +import { Meta } from "./common/colorScheme" +import { colorRamp, createColorScheme } from "./common/ramps" +import { metaCommon, name, buildSyntax, Variant } from "./common/atelier-common" + +const variant: Variant = { + meta: { + name: `${name} Lakeside Dark`, + ...metaCommon, + url: "https://atelierbram.github.io/syntax-highlighting/atelier-schemes/lakeside/", + }, + colors: { + base00: "#161b1d", + base01: "#1f292e", + base02: "#516d7b", + base03: "#5a7b8c", + base04: "#7195a8", + base05: "#7ea2b4", + base06: "#c1e4f6", + base07: "#ebf8ff", + base08: "#d22d72", + base09: "#935c25", + base0A: "#8a8a0f", + base0B: "#568c3b", + base0C: "#2d8f6f", + base0D: "#257fad", + base0E: "#6b6bb8", + base0F: "#b72dd2" + } +} + +const syntax = buildSyntax(variant) + +const theme = (variant: Variant) => { + const { meta, colors } = variant + + return createColorScheme(meta.name, false, { + neutral: chroma + .scale([ + colors.base00, colors.base01, colors.base02, colors.base03, colors.base04, colors.base05, colors.base06, colors.base07 + ]), + red: colorRamp(chroma(colors.base08)), + orange: colorRamp(chroma(colors.base09)), + yellow: colorRamp(chroma(colors.base0A)), + green: colorRamp(chroma(colors.base0B)), + cyan: colorRamp(chroma(colors.base0C)), + blue: colorRamp(chroma(colors.base0D)), + violet: colorRamp(chroma(colors.base0E)), + magenta: colorRamp(chroma(colors.base0F)), + }, syntax) +} + +export const dark = theme(variant) + +export const meta: Meta = variant.meta diff --git a/styles/src/themes/atelier-plateau-dark.ts b/styles/src/themes/atelier-plateau-dark.ts new file mode 100644 index 0000000000000000000000000000000000000000..22510730e7f5a40a2d42ceb3b53bb37e852fe7c5 --- /dev/null +++ b/styles/src/themes/atelier-plateau-dark.ts @@ -0,0 +1,55 @@ +import chroma from "chroma-js" +import { Meta } from "./common/colorScheme" +import { colorRamp, createColorScheme } from "./common/ramps" +import { metaCommon, name, buildSyntax, Variant } from "./common/atelier-common" + +const variant: Variant = { + meta: { + name: `${name} Plateau Dark`, + ...metaCommon, + url: "https://atelierbram.github.io/syntax-highlighting/atelier-schemes/plateau/", + }, + colors: { + base00: "#1b1818", + base01: "#292424", + base02: "#585050", + base03: "#655d5d", + base04: "#7e7777", + base05: "#8a8585", + base06: "#e7dfdf", + base07: "#f4ecec", + base08: "#ca4949", + base09: "#b45a3c", + base0A: "#a06e3b", + base0B: "#4b8b8b", + base0C: "#5485b6", + base0D: "#7272ca", + base0E: "#8464c4", + base0F: "#bd5187" + } +} + +const syntax = buildSyntax(variant) + +const theme = (variant: Variant) => { + const { meta, colors } = variant + + return createColorScheme(meta.name, false, { + neutral: chroma + .scale([ + colors.base00, colors.base01, colors.base02, colors.base03, colors.base04, colors.base05, colors.base06, colors.base07 + ]), + red: colorRamp(chroma(colors.base08)), + orange: colorRamp(chroma(colors.base09)), + yellow: colorRamp(chroma(colors.base0A)), + green: colorRamp(chroma(colors.base0B)), + cyan: colorRamp(chroma(colors.base0C)), + blue: colorRamp(chroma(colors.base0D)), + violet: colorRamp(chroma(colors.base0E)), + magenta: colorRamp(chroma(colors.base0F)), + }, syntax) +} + +export const dark = theme(variant) + +export const meta: Meta = variant.meta diff --git a/styles/src/themes/atelier-savanna-dark.ts b/styles/src/themes/atelier-savanna-dark.ts new file mode 100644 index 0000000000000000000000000000000000000000..c2fa1efa6d958f2f61b3fe1e124fc25e22425e26 --- /dev/null +++ b/styles/src/themes/atelier-savanna-dark.ts @@ -0,0 +1,55 @@ +import chroma from "chroma-js" +import { Meta } from "./common/colorScheme" +import { colorRamp, createColorScheme } from "./common/ramps" +import { metaCommon, name, buildSyntax, Variant } from "./common/atelier-common" + +const variant: Variant = { + meta: { + name: `${name} Savanna Dark`, + ...metaCommon, + url: "https://atelierbram.github.io/syntax-highlighting/atelier-schemes/savanna/", + }, + colors: { + base00: "#171c19", + base01: "#232a25", + base02: "#526057", + base03: "#5f6d64", + base04: "#78877d", + base05: "#87928a", + base06: "#dfe7e2", + base07: "#ecf4ee", + base08: "#b16139", + base09: "#9f713c", + base0A: "#a07e3b", + base0B: "#489963", + base0C: "#1c9aa0", + base0D: "#478c90", + base0E: "#55859b", + base0F: "#867469" + } +} + +const syntax = buildSyntax(variant) + +const theme = (variant: Variant) => { + const { meta, colors } = variant + + return createColorScheme(meta.name, false, { + neutral: chroma + .scale([ + colors.base00, colors.base01, colors.base02, colors.base03, colors.base04, colors.base05, colors.base06, colors.base07 + ]), + red: colorRamp(chroma(colors.base08)), + orange: colorRamp(chroma(colors.base09)), + yellow: colorRamp(chroma(colors.base0A)), + green: colorRamp(chroma(colors.base0B)), + cyan: colorRamp(chroma(colors.base0C)), + blue: colorRamp(chroma(colors.base0D)), + violet: colorRamp(chroma(colors.base0E)), + magenta: colorRamp(chroma(colors.base0F)), + }, syntax) +} + +export const dark = theme(variant) + +export const meta: Meta = variant.meta diff --git a/styles/src/themes/atelier-seaside-dark.ts b/styles/src/themes/atelier-seaside-dark.ts new file mode 100644 index 0000000000000000000000000000000000000000..29bdcfb447b9e1b1ac266dedd1df7808ecef64ec --- /dev/null +++ b/styles/src/themes/atelier-seaside-dark.ts @@ -0,0 +1,55 @@ +import chroma from "chroma-js" +import { Meta } from "./common/colorScheme" +import { colorRamp, createColorScheme } from "./common/ramps" +import { metaCommon, name, buildSyntax, Variant } from "./common/atelier-common" + +const variant: Variant = { + meta: { + name: `${name} Seaside Dark`, + ...metaCommon, + url: "https://atelierbram.github.io/syntax-highlighting/atelier-schemes/savanna/", + }, + colors: { + base00: "#131513", + base01: "#242924", + base02: "#5e6e5e", + base03: "#687d68", + base04: "#809980", + base05: "#8ca68c", + base06: "#cfe8cf", + base07: "#f4fbf4", + base08: "#e6193c", + base09: "#87711d", + base0A: "#98981b", + base0B: "#29a329", + base0C: "#1999b3", + base0D: "#3d62f5", + base0E: "#ad2bee", + base0F: "#e619c3" + } +} + +const syntax = buildSyntax(variant) + +const theme = (variant: Variant) => { + const { meta, colors } = variant + + return createColorScheme(meta.name, false, { + neutral: chroma + .scale([ + colors.base00, colors.base01, colors.base02, colors.base03, colors.base04, colors.base05, colors.base06, colors.base07 + ]), + red: colorRamp(chroma(colors.base08)), + orange: colorRamp(chroma(colors.base09)), + yellow: colorRamp(chroma(colors.base0A)), + green: colorRamp(chroma(colors.base0B)), + cyan: colorRamp(chroma(colors.base0C)), + blue: colorRamp(chroma(colors.base0D)), + violet: colorRamp(chroma(colors.base0E)), + magenta: colorRamp(chroma(colors.base0F)), + }, syntax) +} + +export const dark = theme(variant) + +export const meta: Meta = variant.meta From 5892f1660218fef98214bfc7c4551deceb30a704 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Tue, 7 Mar 2023 14:02:42 -0800 Subject: [PATCH 28/93] Add test for base keymap setting --- crates/settings/src/settings_file.rs | 143 ++++++++++++++++++++++++++- 1 file changed, 142 insertions(+), 1 deletion(-) diff --git a/crates/settings/src/settings_file.rs b/crates/settings/src/settings_file.rs index 575e9499d38a26008bea65a86907bbd31306db1c..1b05993bd5f8059a0ad326dddab6023bb511b0a2 100644 --- a/crates/settings/src/settings_file.rs +++ b/crates/settings/src/settings_file.rs @@ -54,10 +54,151 @@ impl SettingsFile { #[cfg(test)] mod tests { use super::*; - use crate::{watched_json::watch_settings_file, EditorSettings, Settings, SoftWrap}; + use crate::{ + watch_files, watched_json::watch_settings_file, EditorSettings, Settings, SoftWrap, + }; use fs::FakeFs; + use gpui::{actions, Action}; use theme::ThemeRegistry; + #[gpui::test] + async fn test_base_keymap(cx: &mut gpui::TestAppContext) { + let executor = cx.background(); + let fs = FakeFs::new(executor.clone()); + let font_cache = cx.font_cache(); + + actions!(test, [A, B]); + // From the Atom keymap + actions!(workspace, [ActivatePreviousPane]); + // From the JetBrains keymap + actions!(pane, [ActivatePrevItem]); + + fs.save( + "/settings.json".as_ref(), + &r#" + { + "base_keymap": "Atom" + } + "# + .into(), + Default::default(), + ) + .await + .unwrap(); + + fs.save( + "/keymap.json".as_ref(), + &r#" + [ + { + "bindings": { + "backspace": "test::A" + } + } + ] + "# + .into(), + Default::default(), + ) + .await + .unwrap(); + + let settings_file = + WatchedJsonFile::new(fs.clone(), &executor, "/settings.json".as_ref()).await; + let keymaps_file = + WatchedJsonFile::new(fs.clone(), &executor, "/keymap.json".as_ref()).await; + + let default_settings = cx.read(Settings::test); + + cx.update(|cx| { + cx.add_global_action(|_: &A, _cx| { + }); + cx.add_global_action(|_: &B, _cx| { + }); + cx.add_global_action(|_: &ActivatePreviousPane, _cx| { + }); + cx.add_global_action(|_: &ActivatePrevItem, _cx| { + }); + watch_files( + default_settings, + settings_file, + ThemeRegistry::new((), font_cache), + keymaps_file, + cx, + ) + }); + + cx.foreground().run_until_parked(); + + // Test loading the keymap base at all + cx.update(|cx| { + assert_keybindings_for(cx, vec![("backspace", &A), ("k", &ActivatePreviousPane)], line!()); + }); + + // Test modifying the users keymap, while retaining the base keymap + fs.save( + "/keymap.json".as_ref(), + &r#" + [ + { + "bindings": { + "backspace": "test::B" + } + } + ] + "# + .into(), + Default::default(), + ) + .await + .unwrap(); + + cx.foreground().run_until_parked(); + + cx.update(|cx| { + assert_keybindings_for(cx, vec![("backspace", &B), ("k", &ActivatePreviousPane)], line!()); + }); + + // Test modifying the base, while retaining the users keymap + fs.save( + "/settings.json".as_ref(), + &r#" + { + "base_keymap": "JetBrains" + } + "# + .into(), + Default::default(), + ) + .await + .unwrap(); + + cx.foreground().run_until_parked(); + + cx.update(|cx| { + assert_keybindings_for(cx, vec![("backspace", &B), ("[", &ActivatePrevItem)], line!()); + }); + } + + fn assert_keybindings_for<'a>( + cx: &mut MutableAppContext, + actions: Vec<(&'static str, &'a dyn Action)>, + line: u32, + ) { + + for (key, action) in actions { + // assert that... + assert!(cx.available_actions(0, 0).any(|(_, bound_action, b)| { + // action names match... + bound_action.name() == action.name() + && bound_action.namespace() == action.namespace() + // and key strokes contain the given key + && b.iter() + .any(|binding| binding.keystrokes().iter().any(|k| k.key == key)) + }), "On {} Failed to find {} with keybinding {}", line, action.name(), key); + } + } + #[gpui::test] async fn test_watch_settings_files(cx: &mut gpui::TestAppContext) { let executor = cx.background(); From ab4b3293d16f015e66fe9bfd77a30c8e3a9bb023 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Tue, 7 Mar 2023 14:49:05 -0800 Subject: [PATCH 29/93] Fix project panel button and style it Co-authored-by: max --- crates/project/src/worktree.rs | 2 +- crates/project_panel/src/project_panel.rs | 130 ++++++++++------------ crates/settings/src/settings_file.rs | 51 +++++---- crates/theme/src/theme.rs | 1 + crates/workspace/src/workspace.rs | 1 + crates/zed/src/main.rs | 1 - styles/src/styleTree/projectPanel.ts | 33 ++++++ 7 files changed, 127 insertions(+), 92 deletions(-) diff --git a/crates/project/src/worktree.rs b/crates/project/src/worktree.rs index 8b622ab607db49f6f5b54845ccf7d70397752225..d53e84f6b1ee22e973f13308b3b789c4a043c080 100644 --- a/crates/project/src/worktree.rs +++ b/crates/project/src/worktree.rs @@ -867,7 +867,7 @@ impl LocalWorktree { let old_path = self.entry_for_id(entry_id)?.path.clone(); let new_path = new_path.into(); let abs_old_path = self.absolutize(&old_path); - let abs_new_path = self.absolutize(&new_path); + let abs_new_path = self.absolutize(new_path.as_ref()); let rename = cx.background().spawn({ let fs = self.fs.clone(); let abs_new_path = abs_new_path.clone(); diff --git a/crates/project_panel/src/project_panel.rs b/crates/project_panel/src/project_panel.rs index 9df6581d209c47b4e3763ca9acf12da1ce378189..5de68b12fd243e494ffa7cbc52aad1c27144450d 100644 --- a/crates/project_panel/src/project_panel.rs +++ b/crates/project_panel/src/project_panel.rs @@ -5,9 +5,8 @@ use futures::stream::StreamExt; use gpui::{ actions, anyhow::{anyhow, Result}, - color::Color, elements::{ - AnchorCorner, Canvas, ChildView, ConstrainedBox, ContainerStyle, Empty, Flex, + AnchorCorner, ChildView, ConstrainedBox, Container, ContainerStyle, Empty, Flex, KeystrokeLabel, Label, MouseEventHandler, ParentElement, ScrollTarget, Stack, Svg, UniformList, UniformListState, }, @@ -15,7 +14,7 @@ use gpui::{ impl_internal_actions, keymap_matcher::KeymapContext, platform::CursorStyle, - AppContext, ClipboardItem, Element, ElementBox, Entity, ModelHandle, MouseButton, + Action, AppContext, ClipboardItem, Element, ElementBox, Entity, ModelHandle, MouseButton, MutableAppContext, PromptLevel, RenderContext, Task, View, ViewContext, ViewHandle, }; use menu::{Confirm, SelectNext, SelectPrev}; @@ -29,7 +28,7 @@ use std::{ path::{Path, PathBuf}, sync::Arc, }; -use theme::ProjectPanelEntry; +use theme::{ContainedText, ProjectPanelEntry}; use unicase::UniCase; use workspace::Workspace; @@ -1317,79 +1316,36 @@ impl View for ProjectPanel { .boxed() } else { let parent_view_id = cx.handle().id(); - Stack::new() + Flex::column() .with_child( - MouseEventHandler::::new(1, cx, |_, cx| { - Stack::new() - .with_child( - Canvas::new(|bounds, _visible_bounds, cx| { - cx.scene.push_quad(gpui::Quad { - bounds, - background: Some(Color::transparent_black()), - ..Default::default() - }) - }) - .boxed(), - ) - .with_child( - MouseEventHandler::::new(2, cx, |state, cx| { - let style = &cx - .global::() - .theme - .search - .option_button - .style_for(state, false); - - let context_menu_item = cx - .global::() - .theme - .context_menu - .clone() - .item - .style_for(state, true) - .clone(); - - Flex::row() - .with_child( - Label::new( - "Open a new project!".to_string(), - context_menu_item.label.clone(), - ) - .contained() - .boxed(), - ) - .with_child({ - KeystrokeLabel::new( - cx.window_id(), - parent_view_id, - Box::new(workspace::Open), - context_menu_item.keystroke.container, - context_menu_item.keystroke.text.clone(), - ) - .flex_float() - .boxed() - }) - .contained() - .with_style(style.container) - .aligned() - .top() - .constrained() - .with_width(100.) - .with_height(20.) - .boxed() - }) - .on_click(MouseButton::Left, move |_, cx| { - cx.dispatch_action(workspace::Open) - }) - .with_cursor_style(CursorStyle::PointingHand) - .boxed(), + MouseEventHandler::::new(2, cx, { + let button_style = theme.open_project_button.clone(); + let context_menu_item_style = + cx.global::().theme.context_menu.item.clone(); + move |state, cx| { + let button_style = button_style.style_for(state, false).clone(); + let context_menu_item = + context_menu_item_style.style_for(state, true).clone(); + + keystroke_label( + parent_view_id, + "Open a new project", + &button_style, + context_menu_item.keystroke, + workspace::Open, + cx, ) .boxed() + } }) - // TODO is this nescessary? - .on_click(MouseButton::Left, |_, cx| cx.focus_parent_view()) + .on_click(MouseButton::Left, move |_, cx| { + cx.dispatch_action(workspace::Open) + }) + .with_cursor_style(CursorStyle::PointingHand) .boxed(), ) + .contained() + .with_style(container_style) .boxed() } } @@ -1401,6 +1357,38 @@ impl View for ProjectPanel { } } +fn keystroke_label( + view_id: usize, + label_text: &'static str, + label_style: &ContainedText, + keystroke_style: ContainedText, + action: A, + cx: &mut RenderContext, +) -> Container +where + A: Action, +{ + Flex::row() + .with_child( + Label::new(label_text, label_style.text.clone()) + .contained() + .boxed(), + ) + .with_child({ + KeystrokeLabel::new( + cx.window_id(), + view_id, + Box::new(action), + keystroke_style.container, + keystroke_style.text.clone(), + ) + .flex_float() + .boxed() + }) + .contained() + .with_style(label_style.container) +} + impl Entity for ProjectPanel { type Event = Event; } diff --git a/crates/settings/src/settings_file.rs b/crates/settings/src/settings_file.rs index 1b05993bd5f8059a0ad326dddab6023bb511b0a2..50638205c519f5f882f963baeeb45c943e2895e6 100644 --- a/crates/settings/src/settings_file.rs +++ b/crates/settings/src/settings_file.rs @@ -111,14 +111,10 @@ mod tests { let default_settings = cx.read(Settings::test); cx.update(|cx| { - cx.add_global_action(|_: &A, _cx| { - }); - cx.add_global_action(|_: &B, _cx| { - }); - cx.add_global_action(|_: &ActivatePreviousPane, _cx| { - }); - cx.add_global_action(|_: &ActivatePrevItem, _cx| { - }); + cx.add_global_action(|_: &A, _cx| {}); + cx.add_global_action(|_: &B, _cx| {}); + cx.add_global_action(|_: &ActivatePreviousPane, _cx| {}); + cx.add_global_action(|_: &ActivatePrevItem, _cx| {}); watch_files( default_settings, settings_file, @@ -132,7 +128,11 @@ mod tests { // Test loading the keymap base at all cx.update(|cx| { - assert_keybindings_for(cx, vec![("backspace", &A), ("k", &ActivatePreviousPane)], line!()); + assert_keybindings_for( + cx, + vec![("backspace", &A), ("k", &ActivatePreviousPane)], + line!(), + ); }); // Test modifying the users keymap, while retaining the base keymap @@ -152,13 +152,17 @@ mod tests { ) .await .unwrap(); - + cx.foreground().run_until_parked(); cx.update(|cx| { - assert_keybindings_for(cx, vec![("backspace", &B), ("k", &ActivatePreviousPane)], line!()); + assert_keybindings_for( + cx, + vec![("backspace", &B), ("k", &ActivatePreviousPane)], + line!(), + ); }); - + // Test modifying the base, while retaining the users keymap fs.save( "/settings.json".as_ref(), @@ -172,11 +176,15 @@ mod tests { ) .await .unwrap(); - + cx.foreground().run_until_parked(); cx.update(|cx| { - assert_keybindings_for(cx, vec![("backspace", &B), ("[", &ActivatePrevItem)], line!()); + assert_keybindings_for( + cx, + vec![("backspace", &B), ("[", &ActivatePrevItem)], + line!(), + ); }); } @@ -185,17 +193,22 @@ mod tests { actions: Vec<(&'static str, &'a dyn Action)>, line: u32, ) { - for (key, action) in actions { // assert that... - assert!(cx.available_actions(0, 0).any(|(_, bound_action, b)| { - // action names match... - bound_action.name() == action.name() + assert!( + cx.available_actions(0, 0).any(|(_, bound_action, b)| { + // action names match... + bound_action.name() == action.name() && bound_action.namespace() == action.namespace() // and key strokes contain the given key && b.iter() .any(|binding| binding.keystrokes().iter().any(|k| k.key == key)) - }), "On {} Failed to find {} with keybinding {}", line, action.name(), key); + }), + "On {} Failed to find {} with keybinding {}", + line, + action.name(), + key + ); } } diff --git a/crates/theme/src/theme.rs b/crates/theme/src/theme.rs index 43a10978d6fd1a36e03d59b5dda4523e13d30d10..e7252fbf61eff3da14f93731452eed6094f793ce 100644 --- a/crates/theme/src/theme.rs +++ b/crates/theme/src/theme.rs @@ -346,6 +346,7 @@ pub struct ProjectPanel { pub cut_entry: Interactive, pub filename_editor: FieldEditor, pub indent_width: f32, + pub open_project_button: Interactive, } #[derive(Clone, Debug, Deserialize, Default)] diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index e74bcdc1773d3caac4f3f9724607f93e2240736e..f987d00ef1f67bd705e93c6de1121434add32d8a 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -2815,6 +2815,7 @@ fn open(_: &Open, cx: &mut MutableAppContext) { directories: true, multiple: true, }); + cx.spawn(|mut cx| async move { if let Some(paths) = paths.recv().await.flatten() { cx.update(|cx| cx.dispatch_global_action(OpenPaths { paths })); diff --git a/crates/zed/src/main.rs b/crates/zed/src/main.rs index 8407bd45167e239f950c3c987a21bd3c7f92a266..1b794b3857e2bad97158942aad6e12798d929eeb 100644 --- a/crates/zed/src/main.rs +++ b/crates/zed/src/main.rs @@ -237,7 +237,6 @@ fn main() { let app_state = app_state.clone(); async move { while let Some(paths) = open_paths_rx.next().await { - log::error!("OPEN PATHS FROM HANDLE"); cx.update(|cx| workspace::open_paths(&paths, &app_state, cx)) .detach(); } diff --git a/styles/src/styleTree/projectPanel.ts b/styles/src/styleTree/projectPanel.ts index 90e0c82f5bf1d16e19acfa0c3df0a0454cabae86..2601a12691683c6e5dd85cdc5b99257c91d3165d 100644 --- a/styles/src/styleTree/projectPanel.ts +++ b/styles/src/styleTree/projectPanel.ts @@ -29,6 +29,39 @@ export default function projectPanel(colorScheme: ColorScheme) { } return { + openProjectButton: { + ...text(layer, "mono", "active", { size: "sm" }), + background: background(layer, "on"), + cornerRadius: 6, + border: border(layer, "on"), + margin: { + top: 20, + left: 10, + right: 10 + }, + padding: { + bottom: 2, + left: 10, + right: 10, + top: 2, + }, + active: { + ...text(layer, "mono", "on", "inverted"), + background: background(layer, "on", "inverted"), + border: border(layer, "on", "inverted"), + }, + clicked: { + ...text(layer, "mono", "on", "pressed"), + background: background(layer, "on", "pressed"), + border: border(layer, "on", "pressed"), + }, + hover: { + ...text(layer, "mono", "on", "hovered"), + background: background(layer, "on", "hovered"), + border: border(layer, "on", "hovered"), + }, + + }, background: background(layer), padding: { left: 12, right: 12, top: 6, bottom: 6 }, indentWidth: 8, From d173b1d4120cd5313104150e19ca0a9d31f2df35 Mon Sep 17 00:00:00 2001 From: Julia Date: Tue, 7 Mar 2023 18:56:03 -0500 Subject: [PATCH 30/93] Update db followers table when user leaves a project Co-Authored-By: Nathan Sobo --- crates/collab/src/db.rs | 43 ++++-- crates/collab/src/rpc.rs | 4 +- crates/collab/src/tests/integration_tests.rs | 123 +++++++++++++++--- crates/gpui/src/app/test_app_context.rs | 15 ++- .../workspace/src/dock/toggle_dock_button.rs | 2 +- 5 files changed, 156 insertions(+), 31 deletions(-) diff --git a/crates/collab/src/db.rs b/crates/collab/src/db.rs index c4ff2e39188a1133cc086b00ab5194d242ef0cc8..1d0fc377ab67e96b43265a21f7886ac1d7b6f4b7 100644 --- a/crates/collab/src/db.rs +++ b/crates/collab/src/db.rs @@ -1757,17 +1757,14 @@ impl Database { .add(follower::Column::ProjectId.eq(project_id)) .add( follower::Column::LeaderConnectionServerId - .eq(leader_connection.owner_id) - .and(follower::Column::LeaderConnectionId.eq(leader_connection.id)), + .eq(leader_connection.owner_id), ) + .add(follower::Column::LeaderConnectionId.eq(leader_connection.id)) .add( follower::Column::FollowerConnectionServerId - .eq(follower_connection.owner_id) - .and( - follower::Column::FollowerConnectionId - .eq(follower_connection.id), - ), - ), + .eq(follower_connection.owner_id), + ) + .add(follower::Column::FollowerConnectionId.eq(follower_connection.id)), ) .exec(&*tx) .await?; @@ -2560,7 +2557,7 @@ impl Database { &self, project_id: ProjectId, connection: ConnectionId, - ) -> Result> { + ) -> Result> { let room_id = self.room_id_for_project(project_id).await?; self.room_transaction(room_id, |tx| async move { let result = project_collaborator::Entity::delete_many() @@ -2592,13 +2589,39 @@ impl Database { .map(|collaborator| collaborator.connection()) .collect(); + follower::Entity::delete_many() + .filter( + Condition::any() + .add( + Condition::all() + .add(follower::Column::ProjectId.eq(project_id)) + .add( + follower::Column::LeaderConnectionServerId + .eq(connection.owner_id), + ) + .add(follower::Column::LeaderConnectionId.eq(connection.id)), + ) + .add( + Condition::all() + .add(follower::Column::ProjectId.eq(project_id)) + .add( + follower::Column::FollowerConnectionServerId + .eq(connection.owner_id), + ) + .add(follower::Column::FollowerConnectionId.eq(connection.id)), + ), + ) + .exec(&*tx) + .await?; + + let room = self.get_room(project.room_id, &tx).await?; let left_project = LeftProject { id: project_id, host_user_id: project.host_user_id, host_connection_id: project.host_connection()?, connection_ids, }; - Ok(left_project) + Ok((room, left_project)) }) .await } diff --git a/crates/collab/src/rpc.rs b/crates/collab/src/rpc.rs index 710ddcb890010342c4442e2154c7855e3f978afd..d13487440fe42c56808012345e008109589ea7b2 100644 --- a/crates/collab/src/rpc.rs +++ b/crates/collab/src/rpc.rs @@ -1408,7 +1408,7 @@ async fn leave_project(request: proto::LeaveProject, session: Session) -> Result let sender_id = session.connection_id; let project_id = ProjectId::from_proto(request.project_id); - let project = session + let (room, project) = &*session .db() .await .leave_project(project_id, sender_id) @@ -1419,7 +1419,9 @@ async fn leave_project(request: proto::LeaveProject, session: Session) -> Result host_connection_id = %project.host_connection_id, "leave project" ); + project_left(&project, &session); + room_updated(&room, &session.peer); Ok(()) } diff --git a/crates/collab/src/tests/integration_tests.rs b/crates/collab/src/tests/integration_tests.rs index 28266824e388ec4e5d88a26e88b14d918e929af7..4f027af758187fc5581349a71bdac00e79516301 100644 --- a/crates/collab/src/tests/integration_tests.rs +++ b/crates/collab/src/tests/integration_tests.rs @@ -5792,11 +5792,12 @@ async fn test_contact_requests( } #[gpui::test(iterations = 10)] -async fn test_following( +async fn test_basic_following( deterministic: Arc, cx_a: &mut TestAppContext, cx_b: &mut TestAppContext, cx_c: &mut TestAppContext, + cx_d: &mut TestAppContext, ) { deterministic.forbid_parking(); cx_a.update(editor::init); @@ -5806,11 +5807,14 @@ async fn test_following( 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; + let client_d = server.create_client(cx_d, "user_d").await; server - .create_room(&mut [(&client_a, cx_a), (&client_b, cx_b)]) - .await; - server - .make_contacts(&mut [(&client_a, cx_a), (&client_c, cx_c)]) + .create_room(&mut [ + (&client_a, cx_a), + (&client_b, cx_b), + (&client_c, cx_c), + (&client_d, cx_d), + ]) .await; let active_call_a = cx_a.read(ActiveCall::global); let active_call_b = cx_b.read(ActiveCall::global); @@ -5877,6 +5881,7 @@ async fn test_following( let peer_id_a = client_a.peer_id().unwrap(); let peer_id_b = client_b.peer_id().unwrap(); let peer_id_c = client_c.peer_id().unwrap(); + let peer_id_d = client_d.peer_id().unwrap(); // Client A updates their selections in those editors editor_a1.update(cx_a, |editor, cx| { @@ -5896,25 +5901,15 @@ async fn test_following( .await .unwrap(); - // Client A invites client C to the call. - active_call_a - .update(cx_a, |call, cx| { - call.invite(client_c.current_user_id(cx_c).to_proto(), None, cx) - }) - .await - .unwrap(); cx_c.foreground().run_until_parked(); let active_call_c = cx_c.read(ActiveCall::global); - active_call_c - .update(cx_c, |call, cx| call.accept_incoming(cx)) - .await - .unwrap(); let project_c = client_c.build_remote_project(project_id, cx_c).await; let workspace_c = client_c.build_workspace(&project_c, cx_c); active_call_c .update(cx_c, |call, cx| call.set_location(Some(&project_c), cx)) .await .unwrap(); + drop(project_c); // Client C also follows client A. workspace_c @@ -5926,12 +5921,23 @@ async fn test_following( .await .unwrap(); + cx_d.foreground().run_until_parked(); + let active_call_d = cx_d.read(ActiveCall::global); + let project_d = client_d.build_remote_project(project_id, cx_d).await; + let workspace_d = client_d.build_workspace(&project_d, cx_d); + active_call_d + .update(cx_d, |call, cx| call.set_location(Some(&project_d), cx)) + .await + .unwrap(); + drop(project_d); + // All clients see that clients B and C are following client A. cx_c.foreground().run_until_parked(); for (name, active_call, cx) in [ ("A", &active_call_a, &cx_a), ("B", &active_call_b, &cx_b), ("C", &active_call_c, &cx_c), + ("D", &active_call_d, &cx_d), ] { active_call.read_with(*cx, |call, cx| { let room = call.room().unwrap().read(cx); @@ -5954,6 +5960,7 @@ async fn test_following( ("A", &active_call_a, &cx_a), ("B", &active_call_b, &cx_b), ("C", &active_call_c, &cx_c), + ("D", &active_call_d, &cx_d), ] { active_call.read_with(*cx, |call, cx| { let room = call.room().unwrap().read(cx); @@ -5965,6 +5972,90 @@ async fn test_following( }); } + // Client C re-follows client A. + workspace_c.update(cx_c, |workspace, cx| { + workspace.toggle_follow(&ToggleFollow(peer_id_a), cx); + }); + + // All clients see that clients B and C are following client A. + cx_c.foreground().run_until_parked(); + for (name, active_call, cx) in [ + ("A", &active_call_a, &cx_a), + ("B", &active_call_b, &cx_b), + ("C", &active_call_c, &cx_c), + ("D", &active_call_d, &cx_d), + ] { + active_call.read_with(*cx, |call, cx| { + let room = call.room().unwrap().read(cx); + assert_eq!( + room.followers_for(peer_id_a, project_id), + &[peer_id_b, peer_id_c], + "checking followers for A as {name}" + ); + }); + } + + // Client D follows client C. + workspace_d + .update(cx_d, |workspace, cx| { + workspace + .toggle_follow(&ToggleFollow(peer_id_c), cx) + .unwrap() + }) + .await + .unwrap(); + + // All clients see that D is following C + cx_d.foreground().run_until_parked(); + for (name, active_call, cx) in [ + ("A", &active_call_a, &cx_a), + ("B", &active_call_b, &cx_b), + ("C", &active_call_c, &cx_c), + ("D", &active_call_d, &cx_d), + ] { + active_call.read_with(*cx, |call, cx| { + let room = call.room().unwrap().read(cx); + assert_eq!( + room.followers_for(peer_id_c, project_id), + &[peer_id_d], + "checking followers for C as {name}" + ); + }); + } + + // Client C closes the project. + cx_c.drop_last(workspace_c); + + // Clients A and B see that client B is following A, and client C is not present in the followers. + cx_c.foreground().run_until_parked(); + for (name, active_call, cx) in [("A", &active_call_a, &cx_a), ("B", &active_call_b, &cx_b)] { + active_call.read_with(*cx, |call, cx| { + let room = call.room().unwrap().read(cx); + assert_eq!( + room.followers_for(peer_id_a, project_id), + &[peer_id_b], + "checking followers for A as {name}" + ); + }); + } + + // All clients see that no-one is following C + for (name, active_call, cx) in [ + ("A", &active_call_a, &cx_a), + ("B", &active_call_b, &cx_b), + ("C", &active_call_c, &cx_c), + ("D", &active_call_d, &cx_d), + ] { + active_call.read_with(*cx, |call, cx| { + let room = call.room().unwrap().read(cx); + assert_eq!( + room.followers_for(peer_id_c, project_id), + &[], + "checking followers for C as {name}" + ); + }); + } + let editor_b2 = workspace_b.read_with(cx_b, |workspace, cx| { workspace .active_item(cx) diff --git a/crates/gpui/src/app/test_app_context.rs b/crates/gpui/src/app/test_app_context.rs index 1366e7e6edb2877033de15318f3310d164d37967..ad78346991e809751b89d06555ed1f72a97c94c2 100644 --- a/crates/gpui/src/app/test_app_context.rs +++ b/crates/gpui/src/app/test_app_context.rs @@ -18,9 +18,10 @@ use smol::stream::StreamExt; use crate::{ executor, geometry::vector::Vector2F, keymap_matcher::Keystroke, platform, Action, - AnyViewHandle, AppContext, Appearance, Entity, Event, FontCache, InputHandler, KeyDownEvent, - ModelContext, ModelHandle, MutableAppContext, Platform, ReadModelWith, ReadViewWith, - RenderContext, Task, UpdateModel, UpdateView, View, ViewContext, ViewHandle, WeakHandle, + AnyViewHandle, AppContext, Appearance, Entity, Event, FontCache, Handle, InputHandler, + KeyDownEvent, ModelContext, ModelHandle, MutableAppContext, Platform, ReadModelWith, + ReadViewWith, RenderContext, Task, UpdateModel, UpdateView, View, ViewContext, ViewHandle, + WeakHandle, }; use collections::BTreeMap; @@ -329,6 +330,14 @@ impl TestAppContext { .assert_dropped(handle.id()) } + /// Drop a handle, assuming it is the last. If it is not the last, panic with debug information about + /// where the stray handles were created. + pub fn drop_last>(&mut self, handle: H) { + let weak = handle.downgrade(); + self.update(|_| drop(handle)); + self.assert_dropped(weak); + } + fn window_mut(&self, window_id: usize) -> std::cell::RefMut { std::cell::RefMut::map(self.cx.borrow_mut(), |state| { let (_, window) = state diff --git a/crates/workspace/src/dock/toggle_dock_button.rs b/crates/workspace/src/dock/toggle_dock_button.rs index cafbea7db37c6fdccd0e3534bd2c4a2757aef2f0..0b96c3e67b6c2883b5704ed09e12ba23c11ffac4 100644 --- a/crates/workspace/src/dock/toggle_dock_button.rs +++ b/crates/workspace/src/dock/toggle_dock_button.rs @@ -42,6 +42,7 @@ impl View for ToggleDockButton { let workspace = workspace.unwrap(); let dock_position = workspace.read(cx).dock.position; + let dock_pane = workspace.read(cx.app).dock_pane().clone(); let theme = cx.global::().theme.clone(); @@ -67,7 +68,6 @@ impl View for ToggleDockButton { }) .with_cursor_style(CursorStyle::PointingHand) .on_up(MouseButton::Left, move |event, cx| { - let dock_pane = workspace.read(cx.app).dock_pane(); let drop_index = dock_pane.read(cx.app).items_len() + 1; handle_dropped_item(event, &dock_pane.downgrade(), drop_index, false, None, cx); }); From 904993dfc99ef2146357872d0bd9123952e9ca51 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Tue, 7 Mar 2023 16:08:01 -0800 Subject: [PATCH 31/93] Change open paths to replace the existing window if dispatched from a window co-authored-by: Max --- crates/journal/src/journal.rs | 2 +- crates/workspace/src/workspace.rs | 206 ++++++++++++++++++------------ crates/zed/src/main.rs | 6 +- crates/zed/src/zed.rs | 37 +++++- 4 files changed, 162 insertions(+), 89 deletions(-) diff --git a/crates/journal/src/journal.rs b/crates/journal/src/journal.rs index 76a56af93d8c4cdc45a60a31e4ebc007899f61cc..c02d61c3e20b121a1b69589f2334b8b4c1becdb3 100644 --- a/crates/journal/src/journal.rs +++ b/crates/journal/src/journal.rs @@ -48,7 +48,7 @@ pub fn new_journal_entry(app_state: Arc, cx: &mut MutableAppContext) { async move { let (journal_dir, entry_path) = create_entry.await?; let (workspace, _) = cx - .update(|cx| workspace::open_paths(&[journal_dir], &app_state, cx)) + .update(|cx| workspace::open_paths(&[journal_dir], &app_state, None, cx)) .await; let opened = workspace diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index f987d00ef1f67bd705e93c6de1121434add32d8a..65072637ac00b06d96400242051a05c1d7168e8b 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -44,7 +44,8 @@ use gpui::{ platform::{CursorStyle, WindowOptions}, AnyModelHandle, AnyViewHandle, AppContext, AsyncAppContext, Entity, ModelContext, ModelHandle, MouseButton, MutableAppContext, PathPromptOptions, Platform, PromptLevel, RenderContext, - SizeConstraint, Task, View, ViewContext, ViewHandle, WeakViewHandle, WindowBounds, + SizeConstraint, Subscription, Task, View, ViewContext, ViewHandle, WeakViewHandle, + WindowBounds, }; use item::{FollowableItem, FollowableItemHandle, Item, ItemHandle, ProjectItem}; use language::LanguageRegistry; @@ -188,12 +189,54 @@ pub fn init(app_state: Arc, cx: &mut MutableAppContext) { dock::init(cx); notifications::init(cx); - cx.add_global_action(open); + cx.add_global_action(|_: &Open, cx: &mut MutableAppContext| { + let mut paths = cx.prompt_for_paths(PathPromptOptions { + files: true, + directories: true, + multiple: true, + }); + + cx.spawn(|mut cx| async move { + if let Some(paths) = paths.recv().await.flatten() { + cx.update(|cx| cx.dispatch_global_action(OpenPaths { paths })); + } + }) + .detach(); + }); + cx.add_action(|_, _: &Open, cx: &mut ViewContext| { + let mut paths = cx.prompt_for_paths(PathPromptOptions { + files: true, + directories: true, + multiple: true, + }); + + let handle = cx.handle().downgrade(); + cx.spawn(|_, mut cx| async move { + if let Some(paths) = paths.recv().await.flatten() { + cx.update(|cx| { + cx.dispatch_action_at(handle.window_id(), handle.id(), OpenPaths { paths }) + }) + } + }) + .detach(); + }); cx.add_global_action({ let app_state = Arc::downgrade(&app_state); move |action: &OpenPaths, cx: &mut MutableAppContext| { if let Some(app_state) = app_state.upgrade() { - open_paths(&action.paths, &app_state, cx).detach(); + open_paths(&action.paths, &app_state, None, cx).detach(); + } + } + }); + cx.add_action({ + let app_state = Arc::downgrade(&app_state); + move |_, action: &OpenPaths, cx: &mut ViewContext| { + if let Some(app_state) = app_state.upgrade() { + let window_id = cx.window_id(); + let action = action.clone(); + cx.as_mut().defer(move |cx| { + open_paths(&action.paths, &app_state, Some(window_id), cx).detach(); + }) } } }); @@ -488,6 +531,7 @@ pub struct Workspace { active_call: Option<(ModelHandle, Vec)>, leader_updates_tx: mpsc::UnboundedSender<(PeerId, proto::UpdateFollowers)>, database_id: WorkspaceId, + _window_subscriptions: [Subscription; 3], _apply_leader_updates: Task>, _observe_current_user: Task<()>, } @@ -519,10 +563,6 @@ impl Workspace { dock_default_factory: DockDefaultItemFactory, cx: &mut ViewContext, ) -> Self { - cx.observe_fullscreen(|_, _, cx| cx.notify()).detach(); - - cx.observe_window_activation(Self::on_window_activation_changed) - .detach(); cx.observe(&project, |_, _, cx| cx.notify()).detach(); cx.subscribe(&project, move |this, _, event, cx| { match event { @@ -629,6 +669,28 @@ impl Workspace { active_call = Some((call, subscriptions)); } + let subscriptions = [ + cx.observe_fullscreen(|_, _, cx| cx.notify()), + cx.observe_window_activation(Self::on_window_activation_changed), + cx.observe_window_bounds(move |_, mut bounds, display, cx| { + // Transform fixed bounds to be stored in terms of the containing display + if let WindowBounds::Fixed(mut window_bounds) = bounds { + if let Some(screen) = cx.platform().screen_by_id(display) { + let screen_bounds = screen.bounds(); + window_bounds + .set_origin_x(window_bounds.origin_x() - screen_bounds.origin_x()); + window_bounds + .set_origin_y(window_bounds.origin_y() - screen_bounds.origin_y()); + bounds = WindowBounds::Fixed(window_bounds); + } + } + + cx.background() + .spawn(DB.set_window_bounds(workspace_id, bounds, display)) + .detach_and_log_err(cx); + }), + ]; + let mut this = Workspace { modal: None, weak_self: weak_handle.clone(), @@ -660,6 +722,7 @@ impl Workspace { _observe_current_user, _apply_leader_updates, leader_updates_tx, + _window_subscriptions: subscriptions, }; this.project_remote_id_changed(project.read(cx).remote_id(), cx); cx.defer(|this, cx| this.update_window_title(cx)); @@ -676,6 +739,7 @@ impl Workspace { fn new_local( abs_paths: Vec, app_state: Arc, + requesting_window_id: Option, cx: &mut MutableAppContext, ) -> Task<( ViewHandle, @@ -731,42 +795,9 @@ impl Workspace { )) }); - let (bounds, display) = if let Some(bounds) = window_bounds_override { - (Some(bounds), None) - } else { - serialized_workspace - .as_ref() - .and_then(|serialized_workspace| { - let display = serialized_workspace.display?; - let mut bounds = serialized_workspace.bounds?; - - // Stored bounds are relative to the containing display. - // So convert back to global coordinates if that screen still exists - if let WindowBounds::Fixed(mut window_bounds) = bounds { - if let Some(screen) = cx.platform().screen_by_id(display) { - let screen_bounds = screen.bounds(); - window_bounds.set_origin_x( - window_bounds.origin_x() + screen_bounds.origin_x(), - ); - window_bounds.set_origin_y( - window_bounds.origin_y() + screen_bounds.origin_y(), - ); - bounds = WindowBounds::Fixed(window_bounds); - } else { - // Screen no longer exists. Return none here. - return None; - } - } - - Some((bounds, display)) - }) - .unzip() - }; - - // Use the serialized workspace to construct the new window - let (_, workspace) = cx.add_window( - (app_state.build_window_options)(bounds, display, cx.platform().as_ref()), - |cx| { + let build_workspace = + |cx: &mut ViewContext, + serialized_workspace: Option| { let mut workspace = Workspace::new( serialized_workspace, workspace_id, @@ -775,29 +806,53 @@ impl Workspace { cx, ); (app_state.initialize_workspace)(&mut workspace, &app_state, cx); - cx.observe_window_bounds(move |_, mut bounds, display, cx| { - // Transform fixed bounds to be stored in terms of the containing display - if let WindowBounds::Fixed(mut window_bounds) = bounds { - if let Some(screen) = cx.platform().screen_by_id(display) { - let screen_bounds = screen.bounds(); - window_bounds.set_origin_x( - window_bounds.origin_x() - screen_bounds.origin_x(), - ); - window_bounds.set_origin_y( - window_bounds.origin_y() - screen_bounds.origin_y(), - ); - bounds = WindowBounds::Fixed(window_bounds); + workspace + }; + + let workspace = if let Some(window_id) = requesting_window_id { + cx.update(|cx| { + cx.replace_root_view(window_id, |cx| build_workspace(cx, serialized_workspace)) + }) + } else { + let (bounds, display) = if let Some(bounds) = window_bounds_override { + (Some(bounds), None) + } else { + serialized_workspace + .as_ref() + .and_then(|serialized_workspace| { + let display = serialized_workspace.display?; + let mut bounds = serialized_workspace.bounds?; + + // Stored bounds are relative to the containing display. + // So convert back to global coordinates if that screen still exists + if let WindowBounds::Fixed(mut window_bounds) = bounds { + if let Some(screen) = cx.platform().screen_by_id(display) { + let screen_bounds = screen.bounds(); + window_bounds.set_origin_x( + window_bounds.origin_x() + screen_bounds.origin_x(), + ); + window_bounds.set_origin_y( + window_bounds.origin_y() + screen_bounds.origin_y(), + ); + bounds = WindowBounds::Fixed(window_bounds); + } else { + // Screen no longer exists. Return none here. + return None; + } } - } - cx.background() - .spawn(DB.set_window_bounds(workspace_id, bounds, display)) - .detach_and_log_err(cx); - }) - .detach(); - workspace - }, - ); + Some((bounds, display)) + }) + .unzip() + }; + + // Use the serialized workspace to construct the new window + cx.add_window( + (app_state.build_window_options)(bounds, display, cx.platform().as_ref()), + |cx| build_workspace(cx, serialized_workspace), + ) + .1 + }; notify_if_database_failed(&workspace, &mut cx); @@ -893,7 +948,7 @@ impl Workspace { if self.project.read(cx).is_local() { Task::Ready(Some(callback(self, cx))) } else { - let task = Self::new_local(Vec::new(), app_state.clone(), cx); + let task = Self::new_local(Vec::new(), app_state.clone(), None, cx); cx.spawn(|_vh, mut cx| async move { let (workspace, _) = task.await; workspace.update(&mut cx, callback) @@ -2809,21 +2864,6 @@ impl std::fmt::Debug for OpenPaths { } } -fn open(_: &Open, cx: &mut MutableAppContext) { - let mut paths = cx.prompt_for_paths(PathPromptOptions { - files: true, - directories: true, - multiple: true, - }); - - cx.spawn(|mut cx| async move { - if let Some(paths) = paths.recv().await.flatten() { - cx.update(|cx| cx.dispatch_global_action(OpenPaths { paths })); - } - }) - .detach(); -} - pub struct WorkspaceCreated(WeakViewHandle); pub fn activate_workspace_for_project( @@ -2850,6 +2890,7 @@ pub async fn last_opened_workspace_paths() -> Option { pub fn open_paths( abs_paths: &[PathBuf], app_state: &Arc, + requesting_window_id: Option, cx: &mut MutableAppContext, ) -> Task<( ViewHandle, @@ -2880,7 +2921,8 @@ pub fn open_paths( .contains(&false); cx.update(|cx| { - let task = Workspace::new_local(abs_paths, app_state.clone(), cx); + let task = + Workspace::new_local(abs_paths, app_state.clone(), requesting_window_id, cx); cx.spawn(|mut cx| async move { let (workspace, items) = task.await; @@ -2904,7 +2946,7 @@ pub fn open_new( cx: &mut MutableAppContext, init: impl FnOnce(&mut Workspace, &mut ViewContext) + 'static, ) -> Task<()> { - let task = Workspace::new_local(Vec::new(), app_state.clone(), cx); + let task = Workspace::new_local(Vec::new(), app_state.clone(), None, cx); cx.spawn(|mut cx| async move { let (workspace, opened_paths) = task.await; diff --git a/crates/zed/src/main.rs b/crates/zed/src/main.rs index 1b794b3857e2bad97158942aad6e12798d929eeb..13a44fef106a4c357d3c888ec415b5878a66b4e0 100644 --- a/crates/zed/src/main.rs +++ b/crates/zed/src/main.rs @@ -216,7 +216,7 @@ fn main() { cx.spawn(|cx| handle_cli_connection(connection, app_state.clone(), cx)) .detach(); } else if let Ok(Some(paths)) = open_paths_rx.try_next() { - cx.update(|cx| workspace::open_paths(&paths, &app_state, cx)) + cx.update(|cx| workspace::open_paths(&paths, &app_state, None, cx)) .detach(); } else { cx.spawn(|cx| async move { restore_or_create_workspace(cx).await }) @@ -237,7 +237,7 @@ fn main() { let app_state = app_state.clone(); async move { while let Some(paths) = open_paths_rx.next().await { - cx.update(|cx| workspace::open_paths(&paths, &app_state, cx)) + cx.update(|cx| workspace::open_paths(&paths, &app_state, None, cx)) .detach(); } } @@ -603,7 +603,7 @@ async fn handle_cli_connection( paths }; let (workspace, items) = cx - .update(|cx| workspace::open_paths(&paths, &app_state, cx)) + .update(|cx| workspace::open_paths(&paths, &app_state, None, cx)) .await; let mut errored = false; diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index 2fb956f5b6f6ce2c26e5ce0782024c4e367e6bfa..63e026b9abd31dab1a9e0b4a950d841c91d78189 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -728,6 +728,10 @@ mod tests { "ca": null, "cb": null, }, + "d": { + "da": null, + "db": null, + }, }), ) .await; @@ -736,13 +740,14 @@ mod tests { open_paths( &[PathBuf::from("/root/a"), PathBuf::from("/root/b")], &app_state, + None, cx, ) }) .await; assert_eq!(cx.window_ids().len(), 1); - cx.update(|cx| open_paths(&[PathBuf::from("/root/a")], &app_state, cx)) + cx.update(|cx| open_paths(&[PathBuf::from("/root/a")], &app_state, None, cx)) .await; assert_eq!(cx.window_ids().len(), 1); let workspace_1 = cx.root_view::(cx.window_ids()[0]).unwrap(); @@ -756,11 +761,37 @@ mod tests { open_paths( &[PathBuf::from("/root/b"), PathBuf::from("/root/c")], &app_state, + None, + cx, + ) + }) + .await; + assert_eq!(cx.window_ids().len(), 2); + + // Replace existing windows + let window_id = cx.window_ids()[0]; + cx.update(|cx| { + open_paths( + &[PathBuf::from("/root/c"), PathBuf::from("/root/d")], + &app_state, + Some(window_id), cx, ) }) .await; assert_eq!(cx.window_ids().len(), 2); + let workspace_1 = cx.root_view::(window_id).unwrap(); + workspace_1.read_with(cx, |workspace, cx| { + assert_eq!( + workspace + .worktrees(cx) + .map(|w| w.read(cx).abs_path()) + .collect::>(), + &[Path::new("/root/c").into(), Path::new("/root/d").into()] + ); + assert!(workspace.left_sidebar().read(cx).is_open()); + assert!(workspace.active_pane().is_focused(cx)); + }); } #[gpui::test] @@ -772,7 +803,7 @@ mod tests { .insert_tree("/root", json!({"a": "hey"})) .await; - cx.update(|cx| open_paths(&[PathBuf::from("/root/a")], &app_state, cx)) + cx.update(|cx| open_paths(&[PathBuf::from("/root/a")], &app_state, None, cx)) .await; assert_eq!(cx.window_ids().len(), 1); @@ -810,7 +841,7 @@ mod tests { assert!(!cx.is_window_edited(workspace.window_id())); // Opening the buffer again doesn't impact the window's edited state. - cx.update(|cx| open_paths(&[PathBuf::from("/root/a")], &app_state, cx)) + cx.update(|cx| open_paths(&[PathBuf::from("/root/a")], &app_state, None, cx)) .await; let editor = workspace.read_with(cx, |workspace, cx| { workspace From 3594243644c27085c18e8725e1d9402f6bb58357 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Tue, 7 Mar 2023 16:22:13 -0800 Subject: [PATCH 32/93] Fix bug where open would offer to hang up a remote call Co-authored-by: max --- crates/workspace/src/workspace.rs | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index 65072637ac00b06d96400242051a05c1d7168e8b..1c1afea4aad2a58bc40a582053b0b08fa665213d 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -228,16 +228,27 @@ pub fn init(app_state: Arc, cx: &mut MutableAppContext) { } } }); - cx.add_action({ + cx.add_async_action({ let app_state = Arc::downgrade(&app_state); - move |_, action: &OpenPaths, cx: &mut ViewContext| { - if let Some(app_state) = app_state.upgrade() { - let window_id = cx.window_id(); - let action = action.clone(); - cx.as_mut().defer(move |cx| { - open_paths(&action.paths, &app_state, Some(window_id), cx).detach(); - }) + move |workspace, action: &OpenPaths, cx: &mut ViewContext| { + if !workspace.project().read(cx).is_local() { + cx.propagate_action(); + return None; } + + let app_state = app_state.upgrade()?; + let window_id = cx.window_id(); + let action = action.clone(); + let close = workspace.prepare_to_close(false, cx); + + Some(cx.spawn_weak(|_, mut cx| async move { + let can_close = close.await?; + if can_close { + cx.update(|cx| open_paths(&action.paths, &app_state, Some(window_id), cx)) + .await; + } + Ok(()) + })) } }); From 350ddf20257e29bb9e4a55dbf2e380b703557927 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Tue, 7 Mar 2023 17:13:01 -0800 Subject: [PATCH 33/93] Add keymap picker UI Co-authored-by: Max --- Cargo.lock | 2 + crates/project_panel/src/project_panel.rs | 2 +- crates/settings/src/keymap_file.rs | 4 +- crates/settings/src/settings.rs | 46 ++++-- crates/welcome/Cargo.toml | 2 + crates/welcome/src/base_keymap_picker.rs | 175 ++++++++++++++++++++++ crates/welcome/src/welcome.rs | 17 ++- crates/zed/src/zed.rs | 3 +- 8 files changed, 225 insertions(+), 26 deletions(-) create mode 100644 crates/welcome/src/base_keymap_picker.rs diff --git a/Cargo.lock b/Cargo.lock index 2b894eff353636540473d147ecd6a864cd6d1db1..9d950712a894afe51c54611296e5c301645f2457 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8030,9 +8030,11 @@ version = "0.1.0" dependencies = [ "anyhow", "editor", + "fuzzy", "gpui", "install_cli", "log", + "picker", "project", "settings", "theme", diff --git a/crates/project_panel/src/project_panel.rs b/crates/project_panel/src/project_panel.rs index 5de68b12fd243e494ffa7cbc52aad1c27144450d..a95a8b2deb50f624a14b9ca5bdfa9700f603eb49 100644 --- a/crates/project_panel/src/project_panel.rs +++ b/crates/project_panel/src/project_panel.rs @@ -1329,7 +1329,7 @@ impl View for ProjectPanel { keystroke_label( parent_view_id, - "Open a new project", + "Open project", &button_style, context_menu_item.keystroke, workspace::Open, diff --git a/crates/settings/src/keymap_file.rs b/crates/settings/src/keymap_file.rs index 9048719d3f58c9bb3dc91e08d4275e551e0c7b15..2235bc351da078cd53129171b31b963e658962cc 100644 --- a/crates/settings/src/keymap_file.rs +++ b/crates/settings/src/keymap_file.rs @@ -46,8 +46,8 @@ impl KeymapFileContent { Self::load(path, cx).unwrap(); } - if let Some(base_keymap) = cx.global::().base_keymap { - Self::load(base_keymap.asset_path(), cx).log_err(); + if let Some(asset_path) = cx.global::().base_keymap.asset_path() { + Self::load(asset_path, cx).log_err(); } } diff --git a/crates/settings/src/settings.rs b/crates/settings/src/settings.rs index ae6742894899f19c4f738bbee1a563a81858b2eb..49f43e7a2d7b605703489fc292bbb5ad4107df67 100644 --- a/crates/settings/src/settings.rs +++ b/crates/settings/src/settings.rs @@ -55,24 +55,46 @@ pub struct Settings { pub telemetry_defaults: TelemetrySettings, pub telemetry_overrides: TelemetrySettings, pub auto_update: bool, - pub base_keymap: Option, + pub base_keymap: BaseKeymap, } -#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] +#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Default)] pub enum BaseKeymap { + #[default] + VSCode, JetBrains, Sublime, Atom, } impl BaseKeymap { - pub fn asset_path(&self) -> &str { + pub const OPTIONS: [(&'static str, Self); 4] = [ + ("VSCode (Default)", Self::VSCode), + ("Atom", Self::Atom), + ("JetBrains", Self::JetBrains), + ("Sublime", Self::Sublime), + ]; + + pub fn asset_path(&self) -> Option<&'static str> { match self { - BaseKeymap::JetBrains => "keymaps/jetbrains.json", - BaseKeymap::Sublime => "keymaps/sublime_text.json", - BaseKeymap::Atom => "keymaps/atom.json", + BaseKeymap::JetBrains => Some("keymaps/jetbrains.json"), + BaseKeymap::Sublime => Some("keymaps/sublime_text.json"), + BaseKeymap::Atom => Some("keymaps/atom.json"), + BaseKeymap::VSCode => None, } } + + pub fn names() -> impl Iterator { + Self::OPTIONS.iter().map(|(name, _)| *name) + } + + pub fn from_names(option: &str) -> BaseKeymap { + Self::OPTIONS + .iter() + .copied() + .find_map(|(name, value)| (name == option).then(|| value)) + .unwrap_or_default() + } } #[derive(Copy, Clone, Debug, Default, Serialize, Deserialize, JsonSchema)] @@ -455,7 +477,7 @@ impl Settings { merge(&mut self.vim_mode, data.vim_mode); merge(&mut self.autosave, data.autosave); merge(&mut self.default_dock_anchor, data.default_dock_anchor); - merge(&mut self.base_keymap, Some(data.base_keymap)); + merge(&mut self.base_keymap, data.base_keymap); // Ensure terminal font is loaded, so we can request it in terminal_element layout if let Some(terminal_font) = &data.terminal.font_family { @@ -633,7 +655,7 @@ impl Settings { }, telemetry_overrides: Default::default(), auto_update: true, - base_keymap: None, + base_keymap: Default::default(), } } @@ -722,13 +744,7 @@ pub fn parse_json_with_comments(content: &str) -> Result )?) } -/// Expects the key to be unquoted, and the value to be valid JSON -/// (e.g. values should be unquoted for numbers and bools, quoted for strings) -pub fn write_settings_key( - settings_content: &mut String, - key_path: &[&str], - new_value: &T, -) { +fn write_settings_key(settings_content: &mut String, key_path: &[&str], new_value: &Value) { let mut parser = tree_sitter::Parser::new(); parser.set_language(tree_sitter_json::language()).unwrap(); let tree = parser.parse(&settings_content, None).unwrap(); diff --git a/crates/welcome/Cargo.toml b/crates/welcome/Cargo.toml index e76636411bba5188084d7c585419dcd388aab6a4..d3b0e09697ce74bf4c7610d98699fef180f27ab8 100644 --- a/crates/welcome/Cargo.toml +++ b/crates/welcome/Cargo.toml @@ -14,6 +14,7 @@ test-support = [] anyhow = "1.0.38" log = "0.4" editor = { path = "../editor" } +fuzzy = { path = "../fuzzy" } gpui = { path = "../gpui" } install_cli = { path = "../install_cli" } project = { path = "../project" } @@ -21,4 +22,5 @@ settings = { path = "../settings" } theme = { path = "../theme" } theme_selector = { path = "../theme_selector" } util = { path = "../util" } +picker = { path = "../picker" } workspace = { path = "../workspace" } \ No newline at end of file diff --git a/crates/welcome/src/base_keymap_picker.rs b/crates/welcome/src/base_keymap_picker.rs new file mode 100644 index 0000000000000000000000000000000000000000..a37bcb18371c95f8ea8fdc1181ec9d0af3a6409e --- /dev/null +++ b/crates/welcome/src/base_keymap_picker.rs @@ -0,0 +1,175 @@ +use fuzzy::{match_strings, StringMatch, StringMatchCandidate}; +use gpui::{ + actions, + elements::{ChildView, Element as _, Label}, + AnyViewHandle, Entity, MutableAppContext, View, ViewContext, ViewHandle, +}; +use picker::{Picker, PickerDelegate}; +use settings::{settings_file::SettingsFile, BaseKeymap, Settings}; +use workspace::Workspace; + +pub struct BaseKeymapSelector { + matches: Vec, + picker: ViewHandle>, + selected_index: usize, +} + +actions!(welcome, [ToggleBaseKeymapSelector]); + +pub fn init(cx: &mut MutableAppContext) { + Picker::::init(cx); + cx.add_action({ + move |workspace, _: &ToggleBaseKeymapSelector, cx| BaseKeymapSelector::toggle(workspace, cx) + }); +} + +pub enum Event { + Dismissed, +} + +impl BaseKeymapSelector { + fn toggle(workspace: &mut Workspace, cx: &mut ViewContext) { + workspace.toggle_modal(cx, |_, cx| { + let this = cx.add_view(|cx| Self::new(cx)); + cx.subscribe(&this, Self::on_event).detach(); + this + }); + } + + fn new(cx: &mut ViewContext) -> Self { + let base = cx.global::().base_keymap; + let selected_index = BaseKeymap::OPTIONS + .iter() + .position(|(_, value)| *value == base) + .unwrap_or(0); + + let this = cx.weak_handle(); + Self { + picker: cx.add_view(|cx| Picker::new("Select a base keymap", this, cx)), + matches: Vec::new(), + selected_index, + } + } + + fn on_event( + workspace: &mut Workspace, + _: ViewHandle, + event: &Event, + cx: &mut ViewContext, + ) { + match event { + Event::Dismissed => { + workspace.dismiss_modal(cx); + } + } + } +} + +impl Entity for BaseKeymapSelector { + type Event = Event; +} + +impl View for BaseKeymapSelector { + fn ui_name() -> &'static str { + "BaseKeymapSelector" + } + + fn render(&mut self, cx: &mut gpui::RenderContext<'_, Self>) -> gpui::ElementBox { + ChildView::new(self.picker.clone(), cx).boxed() + } + + fn focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext) { + if cx.is_self_focused() { + cx.focus(&self.picker); + } + } +} + +impl PickerDelegate for BaseKeymapSelector { + fn match_count(&self) -> usize { + self.matches.len() + } + + fn selected_index(&self) -> usize { + self.selected_index + } + + fn set_selected_index(&mut self, ix: usize, _: &mut ViewContext) { + self.selected_index = ix; + } + + fn update_matches(&mut self, query: String, cx: &mut ViewContext) -> gpui::Task<()> { + let background = cx.background().clone(); + let candidates = BaseKeymap::names() + .enumerate() + .map(|(id, name)| StringMatchCandidate { + id, + char_bag: name.into(), + string: name.into(), + }) + .collect::>(); + + cx.spawn(|this, mut cx| async move { + let matches = if query.is_empty() { + candidates + .into_iter() + .enumerate() + .map(|(index, candidate)| StringMatch { + candidate_id: index, + string: candidate.string, + positions: Vec::new(), + score: 0.0, + }) + .collect() + } else { + match_strings( + &candidates, + &query, + false, + 100, + &Default::default(), + background, + ) + .await + }; + + this.update(&mut cx, |this, cx| { + this.matches = matches; + this.selected_index = this + .selected_index + .min(this.matches.len().saturating_sub(1)); + cx.notify(); + }); + }) + } + + fn confirm(&mut self, cx: &mut ViewContext) { + if let Some(selection) = self.matches.get(self.selected_index) { + let base_keymap = BaseKeymap::from_names(&selection.string); + SettingsFile::update(cx, move |settings| settings.base_keymap = Some(base_keymap)); + } + cx.emit(Event::Dismissed); + } + + fn dismiss(&mut self, cx: &mut ViewContext) { + cx.emit(Event::Dismissed) + } + + fn render_match( + &self, + ix: usize, + mouse_state: &mut gpui::MouseState, + selected: bool, + cx: &gpui::AppContext, + ) -> gpui::ElementBox { + let theme = &cx.global::().theme; + let keymap_match = &self.matches[ix]; + let style = theme.picker.item.style_for(mouse_state, selected); + + Label::new(keymap_match.string.clone(), style.label.clone()) + .with_highlights(keymap_match.positions.clone()) + .contained() + .with_style(style.container) + .boxed() + } +} diff --git a/crates/welcome/src/welcome.rs b/crates/welcome/src/welcome.rs index 8bb055dad0a7c333f4b590a286d0d6e90baf0ec9..c780a06ee151242337a2ddd50d2f7d55744b4c36 100644 --- a/crates/welcome/src/welcome.rs +++ b/crates/welcome/src/welcome.rs @@ -1,3 +1,5 @@ +mod base_keymap_picker; + use std::borrow::Cow; use gpui::{ @@ -9,11 +11,15 @@ use settings::{settings_file::SettingsFile, Settings, SettingsFileContent}; use theme::CheckboxStyle; use workspace::{item::Item, PaneBackdrop, Welcome, Workspace, WorkspaceId}; +use crate::base_keymap_picker::ToggleBaseKeymapSelector; + pub fn init(cx: &mut MutableAppContext) { cx.add_action(|workspace: &mut Workspace, _: &Welcome, cx| { let welcome_page = cx.add_view(WelcomePage::new); workspace.add_item(Box::new(welcome_page), cx) - }) + }); + + base_keymap_picker::init(cx); } pub struct WelcomePage { @@ -64,9 +70,9 @@ impl View for WelcomePage { .contained() .with_style(theme.welcome.logo_subheading.container) .boxed(), - self.render_cta_button(2, "Choose a theme", theme_selector::Toggle, width, cx), - self.render_cta_button(3, "Choose a keymap", theme_selector::Toggle, width, cx), - self.render_cta_button(4, "Install the CLI", install_cli::Install, width, cx), + self.render_cta_button("Choose a theme", theme_selector::Toggle, width, cx), + self.render_cta_button("Choose a keymap", ToggleBaseKeymapSelector, width, cx), + self.render_cta_button("Install the CLI", install_cli::Install, width, cx), self.render_settings_checkbox::( "Do you want to send telemetry?", &theme.welcome.checkbox, @@ -110,7 +116,6 @@ impl WelcomePage { fn render_cta_button( &self, - region_id: usize, label: L, action: A, width: f32, @@ -121,7 +126,7 @@ impl WelcomePage { A: 'static + Action + Clone, { let theme = cx.global::().theme.clone(); - MouseEventHandler::::new(region_id, cx, |state, _| { + MouseEventHandler::::new(0, cx, |state, _| { let style = theme.welcome.button.style_for(state, false); Label::new(label, style.text.clone()) .aligned() diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index 63e026b9abd31dab1a9e0b4a950d841c91d78189..3b48632265d5437f238bef5a19a48a6841f1cf14 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -35,7 +35,7 @@ use std::{borrow::Cow, env, path::Path, str, sync::Arc}; use util::{channel::ReleaseChannel, paths, ResultExt, StaffMode}; use uuid::Uuid; pub use workspace; -use workspace::{dock::Dock, open_new, sidebar::SidebarSide, AppState, Restart, Workspace}; +use workspace::{open_new, sidebar::SidebarSide, AppState, Restart, Workspace}; pub const FIRST_OPEN: &str = "first_open"; @@ -270,7 +270,6 @@ pub fn init(app_state: &Arc, cx: &mut gpui::MutableAppContext) { workspace.toggle_sidebar(SidebarSide::Left, cx); let welcome_page = cx.add_view(|cx| welcome::WelcomePage::new(cx)); workspace.add_item_to_center(Box::new(welcome_page.clone()), cx); - Dock::move_dock(workspace, settings::DockAnchor::Bottom, false, cx); cx.focus(welcome_page); cx.notify(); }) From b4561b848d05af4908b5f493767f7cad3005610d Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 8 Mar 2023 10:56:40 +0100 Subject: [PATCH 34/93] Limit the number of parallel messages handled for any given connection --- crates/collab/src/rpc.rs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/crates/collab/src/rpc.rs b/crates/collab/src/rpc.rs index d13487440fe42c56808012345e008109589ea7b2..1deaefec1a446857748e311a34ffdd741385c944 100644 --- a/crates/collab/src/rpc.rs +++ b/crates/collab/src/rpc.rs @@ -53,7 +53,7 @@ use std::{ }, time::Duration, }; -use tokio::sync::watch; +use tokio::sync::{watch, Semaphore}; use tower::ServiceBuilder; use tracing::{info_span, instrument, Instrument}; @@ -542,8 +542,13 @@ impl Server { // This arrangement ensures we will attempt to process earlier messages first, but fall // back to processing messages arrived later in the spirit of making progress. let mut foreground_message_handlers = FuturesUnordered::new(); + let concurrent_handlers = Arc::new(Semaphore::new(256)); loop { - let next_message = incoming_rx.next().fuse(); + let next_message = async { + let permit = concurrent_handlers.clone().acquire_owned().await.unwrap(); + let message = incoming_rx.next().await; + (permit, message) + }.fuse(); futures::pin_mut!(next_message); futures::select_biased! { _ = teardown.changed().fuse() => return Ok(()), @@ -554,7 +559,8 @@ impl Server { break; } _ = foreground_message_handlers.next() => {} - message = next_message => { + next_message = next_message => { + let (permit, message) = next_message; if let Some(message) = message { let type_name = message.payload_type_name(); let span = tracing::info_span!("receive message", %user_id, %login, %connection_id, %address, type_name); @@ -564,7 +570,10 @@ impl Server { let handle_message = (handler)(message, session.clone()); drop(span_enter); - let handle_message = handle_message.instrument(span); + let handle_message = async move { + handle_message.await; + drop(permit); + }.instrument(span); if is_background { executor.spawn_detached(handle_message); } else { From a435dc1339bd10e2b43f5bbd89f74950332abcf5 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 8 Mar 2023 16:11:51 +0100 Subject: [PATCH 35/93] Clear selections on buffer only if they hadn't been cleared already --- crates/language/src/buffer.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/crates/language/src/buffer.rs b/crates/language/src/buffer.rs index acccb553d3d14d11e6140fb8e2a81818214e84e1..09a96342271b00f508094b8426ab5ddf81b04131 100644 --- a/crates/language/src/buffer.rs +++ b/crates/language/src/buffer.rs @@ -1353,7 +1353,13 @@ impl Buffer { } pub fn remove_active_selections(&mut self, cx: &mut ModelContext) { - self.set_active_selections(Arc::from([]), false, Default::default(), cx); + if self + .remote_selections + .get(&self.text.replica_id()) + .map_or(true, |set| !set.selections.is_empty()) + { + self.set_active_selections(Arc::from([]), false, Default::default(), cx); + } } pub fn set_text(&mut self, text: T, cx: &mut ModelContext) -> Option From b687aec9d9f79ae7428fc2c7cc0a48d53bb9652e Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Wed, 8 Mar 2023 17:02:12 +0100 Subject: [PATCH 36/93] Avoid saving buffer if it's neither dirty nor in conflict However, keep emitting `Saved` events so that the language server is notified and can perform tasks related to saving (e.g., running `cargo check` in the case of rust-analyzer). --- crates/project/src/project.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index 2ebea8d07dad811a378a065a7f666caaf594c6d3..f93de8e1d847d263dad2526dbcaaa77b0571b118 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -1434,7 +1434,19 @@ impl Project { let worktree = file.worktree.clone(); let path = file.path.clone(); worktree.update(cx, |worktree, cx| match worktree { - Worktree::Local(worktree) => worktree.save_buffer(buffer, path, false, cx), + Worktree::Local(worktree) => { + if buffer.read(cx).is_dirty() || buffer.read(cx).has_conflict() { + worktree.save_buffer(buffer, path, false, cx) + } else { + buffer.update(cx, |buffer, cx| { + let version = buffer.saved_version().clone(); + let fingerprint = buffer.saved_version_fingerprint(); + let mtime = buffer.saved_mtime(); + buffer.did_save(version.clone(), fingerprint, mtime, cx); + Task::ready(Ok((version, fingerprint, mtime))) + }) + } + } Worktree::Remote(worktree) => worktree.save_buffer(buffer, cx), }) } From ae510c80dbc71ad8864ff96b023412444c630346 Mon Sep 17 00:00:00 2001 From: Joseph Lyons Date: Wed, 8 Mar 2023 13:25:32 -0500 Subject: [PATCH 37/93] v0.77.x dev --- Cargo.lock | 2 +- crates/zed/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2e7997458ed00185d5d1b48f2943eb0e657a1b41..f89666c86d0b0b1fcf9b405ca2dfa014767a2c4f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8358,7 +8358,7 @@ checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" [[package]] name = "zed" -version = "0.76.0" +version = "0.77.0" dependencies = [ "activity_indicator", "anyhow", diff --git a/crates/zed/Cargo.toml b/crates/zed/Cargo.toml index 19c9a3d727704176f7d36b216719a3584d8c4a8d..8060c2af115b0aa28b68a36f1d78f30ddfbbadad 100644 --- a/crates/zed/Cargo.toml +++ b/crates/zed/Cargo.toml @@ -3,7 +3,7 @@ authors = ["Nathan Sobo "] description = "The fast, collaborative code editor." edition = "2021" name = "zed" -version = "0.76.0" +version = "0.77.0" publish = false [lib] From 14497027d4ef0f86c7d251e2abf5ac4e24dc8476 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Wed, 8 Mar 2023 12:22:16 -0800 Subject: [PATCH 38/93] collab 0.6.2 --- Cargo.lock | 2 +- crates/collab/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f89666c86d0b0b1fcf9b405ca2dfa014767a2c4f..82a045ed3a9b1d1608ddffe6952f449fd3c07de1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1188,7 +1188,7 @@ dependencies = [ [[package]] name = "collab" -version = "0.6.1" +version = "0.6.2" dependencies = [ "anyhow", "async-tungstenite", diff --git a/crates/collab/Cargo.toml b/crates/collab/Cargo.toml index 86fe9174bf0bfec0aeb5b90daab8d7e09c898bd7..fee7089ce61853fc1104ec5ba3f6c062165d0695 100644 --- a/crates/collab/Cargo.toml +++ b/crates/collab/Cargo.toml @@ -3,7 +3,7 @@ authors = ["Nathan Sobo "] default-run = "collab" edition = "2021" name = "collab" -version = "0.6.1" +version = "0.6.2" publish = false [[bin]] From 9842b7ad1a7f0c6008c9b030e2c7d8db9b63c0a2 Mon Sep 17 00:00:00 2001 From: Nate Butler Date: Wed, 8 Mar 2023 16:34:27 -0500 Subject: [PATCH 39/93] WIP Co-Authored-By: Mikayla Maki --- crates/theme/src/theme.rs | 3 + crates/welcome/src/welcome.rs | 95 ++++++++++------ styles/src/styleTree/welcome.ts | 187 ++++++++++++++++++-------------- 3 files changed, 170 insertions(+), 115 deletions(-) diff --git a/crates/theme/src/theme.rs b/crates/theme/src/theme.rs index e7252fbf61eff3da14f93731452eed6094f793ce..8fc6db3e5bfdaf2730670168a0e63821b0962ecd 100644 --- a/crates/theme/src/theme.rs +++ b/crates/theme/src/theme.rs @@ -858,6 +858,9 @@ pub struct WelcomeStyle { pub logo_subheading: ContainedText, pub checkbox: CheckboxStyle, pub button: Interactive, + pub button_group: ContainerStyle, + pub heading_group: ContainerStyle, + pub checkbox_group: ContainerStyle, } #[derive(Clone, Deserialize, Default)] diff --git a/crates/welcome/src/welcome.rs b/crates/welcome/src/welcome.rs index c780a06ee151242337a2ddd50d2f7d55744b4c36..d5431e5108ca77d7856fff529122085ce74c581d 100644 --- a/crates/welcome/src/welcome.rs +++ b/crates/welcome/src/welcome.rs @@ -54,39 +54,72 @@ impl View for WelcomePage { self_handle.id(), Flex::column() .with_children([ - Image::new("images/zed-logo-90x90.png") - .constrained() - .with_width(90.) - .with_height(90.) - .aligned() + Flex::column() + .with_children([ + Image::new("images/zed-logo-90x90.png") + .constrained() + .with_width(90.) + .with_height(90.) + .aligned() + .contained() + .aligned() + .boxed(), + Label::new( + "Code at the speed of thought", + theme.welcome.logo_subheading.text.clone(), + ) + .aligned() + .contained() + .with_style(theme.welcome.logo_subheading.container) + .boxed(), + ]) .contained() - .aligned() + .with_style(theme.welcome.heading_group) + .boxed(), + Flex::row() + .with_children([ + self.render_cta_button( + "Choose a theme", + theme_selector::Toggle, + width, + cx, + ), + self.render_cta_button( + "Choose a keymap", + ToggleBaseKeymapSelector, + width, + cx, + ), + self.render_cta_button( + "Install the CLI", + install_cli::Install, + width, + cx, + ), + ]) + .contained() + .with_style(theme.welcome.button_group) + .boxed(), + Flex::column() + .with_children([ + self.render_settings_checkbox::( + "Do you want to send telemetry?", + &theme.welcome.checkbox, + metrics, + cx, + |content, checked| content.telemetry.set_metrics(checked), + ), + self.render_settings_checkbox::( + "Send crash reports", + &theme.welcome.checkbox, + diagnostics, + cx, + |content, checked| content.telemetry.set_diagnostics(checked), + ), + ]) + .contained() + .with_style(theme.welcome.checkbox_group) .boxed(), - Label::new( - "Code at the speed of thought", - theme.welcome.logo_subheading.text.clone(), - ) - .aligned() - .contained() - .with_style(theme.welcome.logo_subheading.container) - .boxed(), - self.render_cta_button("Choose a theme", theme_selector::Toggle, width, cx), - self.render_cta_button("Choose a keymap", ToggleBaseKeymapSelector, width, cx), - self.render_cta_button("Install the CLI", install_cli::Install, width, cx), - self.render_settings_checkbox::( - "Do you want to send telemetry?", - &theme.welcome.checkbox, - metrics, - cx, - |content, checked| content.telemetry.set_metrics(checked), - ), - self.render_settings_checkbox::( - "Send crash reports", - &theme.welcome.checkbox, - diagnostics, - cx, - |content, checked| content.telemetry.set_diagnostics(checked), - ), ]) .constrained() .with_max_width(width) diff --git a/styles/src/styleTree/welcome.ts b/styles/src/styleTree/welcome.ts index bfd67cec8d19d29d651e71acfc573f9aa4757c1c..2dc0f59b2e5a432251e630cdd60342807cffd158 100644 --- a/styles/src/styleTree/welcome.ts +++ b/styles/src/styleTree/welcome.ts @@ -4,91 +4,110 @@ import { border, background, foreground, text, TextProperties } from "./componen export default function welcome(colorScheme: ColorScheme) { - let layer = colorScheme.highest; + let layer = colorScheme.highest; - let checkboxBase = { - cornerRadius: 4, - padding: { - left: 3, - right: 3, - top: 3, - bottom: 3, - }, - shadow: colorScheme.popoverShadow, - border: border(layer), - margin: { - right: 8, - top: 5, - bottom: 5 - }, - }; - - let interactive_text_size: TextProperties = { size: "md" } - - return { - pageWidth: 450, - logoSubheading: { - ...text(layer, "sans", { size: "lg" }), - margin: { - top: 10, - bottom: 7, - }, - }, - button: { - background: background(layer), - border: border(layer, "active"), - cornerRadius: 4, - margin: { - top: 8, - bottom: 7 - }, - padding: { - top: 1, - bottom: 1, - left: 7, - right: 7, - }, - ...text(layer, "sans", "hovered", interactive_text_size), - hover: { - ...text(layer, "sans", "hovered", interactive_text_size), - background: background(layer, "hovered"), - border: border(layer, "hovered"), - }, - }, - checkbox: { - label: { - ...text(layer, "sans", interactive_text_size), - // Also supports margin, container, border, etc. - }, - container: { + let checkboxBase = { + cornerRadius: 4, + padding: { + left: 3, + right: 3, + top: 3, + bottom: 3, + }, + // shadow: colorScheme.popoverShadow, + border: border(layer), margin: { - top: 5, + right: 8, + top: 5, + bottom: 5 + }, + }; + + let interactive_text_size: TextProperties = { size: "sm" } + + return { + pageWidth: 320, + logoSubheading: { + ...text(layer, "sans", { size: "lg" }), + margin: { + top: 10, + bottom: 7, + }, + }, + buttonGroup: { + border: border(layer, "active"), + margin: { + top: 8, + bottom: 7 + }, + }, + headingGroup: { + margin: { + top: 8, + bottom: 7 + }, + }, + checkboxGroup: { + margin: { + top: 8, + bottom: 7 + }, + }, + button: { + background: background(layer), + border: border(layer, "default"), + cornerRadius: 4, + margin: { + top: 8, + bottom: 7 + }, + padding: { + top: 1, + bottom: 1, + left: 7, + right: 7, + }, + ...text(layer, "sans", "default", interactive_text_size), + hover: { + ...text(layer, "sans", "default", interactive_text_size), + background: background(layer, "default"), + border: border(layer, "active"), + }, }, - }, - width: 12, - height: 12, - checkIcon: "icons/check_12.svg", - checkIconColor: foreground(layer, "on"), - default: { - ...checkboxBase, - background: background(layer, "default"), - border: border(layer, "active") - }, - checked: { - ...checkboxBase, - background: background(layer, "hovered"), - border: border(layer, "active") - }, - hovered: { - ...checkboxBase, - background: background(layer, "hovered"), - border: border(layer, "hovered") - }, - hoveredAndChecked: { - ...checkboxBase, - background: background(layer, "hovered"), - border: border(layer, "active") - } + checkbox: { + label: { + ...text(layer, "sans", interactive_text_size), + // Also supports margin, container, border, etc. + }, + container: { + margin: { + top: 5, + }, + }, + width: 12, + height: 12, + checkIcon: "icons/check_12.svg", + checkIconColor: foreground(layer, "on"), + default: { + ...checkboxBase, + background: background(layer, "default"), + border: border(layer, "active") + }, + checked: { + ...checkboxBase, + background: background(layer, "hovered"), + border: border(layer, "active") + }, + hovered: { + ...checkboxBase, + background: background(layer, "hovered"), + border: border(layer, "hovered") + }, + hoveredAndChecked: { + ...checkboxBase, + background: background(layer, "hovered"), + border: border(layer, "active") + } + } } - } -} \ No newline at end of file +} From cc33f83e4e311fa454f8543ef14a57276f794162 Mon Sep 17 00:00:00 2001 From: Nate Butler Date: Wed, 8 Mar 2023 16:45:35 -0500 Subject: [PATCH 40/93] Add Zed logo icon Co-Authored-By: Mikayla Maki --- assets/icons/logo_96.svg | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 assets/icons/logo_96.svg diff --git a/assets/icons/logo_96.svg b/assets/icons/logo_96.svg new file mode 100644 index 0000000000000000000000000000000000000000..dc98bb8bc249bfb1decb1771b33470b324dde96f --- /dev/null +++ b/assets/icons/logo_96.svg @@ -0,0 +1,3 @@ + + + From 344f59adf7af52b3f41aa2f37b1c0de798b2d8ef Mon Sep 17 00:00:00 2001 From: Nate Butler Date: Wed, 8 Mar 2023 17:14:15 -0500 Subject: [PATCH 41/93] Tweak welcome design Co-Authored-By: Mikayla Maki --- crates/theme/src/theme.rs | 14 +++++++++++ crates/welcome/src/welcome.rs | 17 +++++++++---- styles/src/styleTree/welcome.ts | 42 +++++++++++++++++++++------------ 3 files changed, 53 insertions(+), 20 deletions(-) diff --git a/crates/theme/src/theme.rs b/crates/theme/src/theme.rs index 8fc6db3e5bfdaf2730670168a0e63821b0962ecd..13546b40cd958f6ff3c75513e4a9689aaa7526c1 100644 --- a/crates/theme/src/theme.rs +++ b/crates/theme/src/theme.rs @@ -855,6 +855,7 @@ pub struct FeedbackStyle { #[derive(Clone, Deserialize, Default)] pub struct WelcomeStyle { pub page_width: f32, + pub logo: IconStyle, pub logo_subheading: ContainedText, pub checkbox: CheckboxStyle, pub button: Interactive, @@ -863,6 +864,19 @@ pub struct WelcomeStyle { pub checkbox_group: ContainerStyle, } +#[derive(Clone, Deserialize, Default)] +pub struct IconStyle { + pub color: Color, + pub icon: String, + pub dimensions: Dimensions, +} + +#[derive(Clone, Deserialize, Default)] +pub struct Dimensions { + pub width: f32, + pub height: f32, +} + #[derive(Clone, Deserialize, Default)] pub struct CheckboxStyle { pub check_icon: String, diff --git a/crates/welcome/src/welcome.rs b/crates/welcome/src/welcome.rs index d5431e5108ca77d7856fff529122085ce74c581d..246ff267171887ad11dbb802222663bbe289e91e 100644 --- a/crates/welcome/src/welcome.rs +++ b/crates/welcome/src/welcome.rs @@ -3,7 +3,7 @@ mod base_keymap_picker; use std::borrow::Cow; use gpui::{ - elements::{Empty, Flex, Image, Label, MouseEventHandler, ParentElement, Svg}, + elements::{Empty, Flex, Label, MouseEventHandler, ParentElement, Svg}, Action, Element, ElementBox, Entity, MouseButton, MutableAppContext, RenderContext, Subscription, View, ViewContext, }; @@ -56,10 +56,11 @@ impl View for WelcomePage { .with_children([ Flex::column() .with_children([ - Image::new("images/zed-logo-90x90.png") + Svg::new(theme.welcome.logo.icon.clone()) + .with_color(theme.welcome.logo.color) .constrained() - .with_width(90.) - .with_height(90.) + .with_width(theme.welcome.logo.dimensions.width) + .with_height(theme.welcome.logo.dimensions.height) .aligned() .contained() .aligned() @@ -75,8 +76,10 @@ impl View for WelcomePage { ]) .contained() .with_style(theme.welcome.heading_group) + .constrained() + .with_width(width) .boxed(), - Flex::row() + Flex::column() .with_children([ self.render_cta_button( "Choose a theme", @@ -99,6 +102,8 @@ impl View for WelcomePage { ]) .contained() .with_style(theme.welcome.button_group) + .constrained() + .with_width(width) .boxed(), Flex::column() .with_children([ @@ -119,6 +124,8 @@ impl View for WelcomePage { ]) .contained() .with_style(theme.welcome.checkbox_group) + .constrained() + .with_width(width) .boxed(), ]) .constrained() diff --git a/styles/src/styleTree/welcome.ts b/styles/src/styleTree/welcome.ts index 2dc0f59b2e5a432251e630cdd60342807cffd158..137c6df11177f8fed9a156acc8b6a5a49d62017d 100644 --- a/styles/src/styleTree/welcome.ts +++ b/styles/src/styleTree/welcome.ts @@ -1,5 +1,6 @@ import { ColorScheme } from "../themes/common/colorScheme"; +import { withOpacity } from "../utils/color"; import { border, background, foreground, text, TextProperties } from "./components"; @@ -27,50 +28,61 @@ export default function welcome(colorScheme: ColorScheme) { return { pageWidth: 320, + logo: { + color: foreground(layer, "default"), + icon: "icons/logo_96.svg", + dimensions: { + width: 64, + height: 64, + } + }, logoSubheading: { - ...text(layer, "sans", { size: "lg" }), + ...text(layer, "sans", "variant", { size: "md" }), margin: { top: 10, bottom: 7, }, }, buttonGroup: { - border: border(layer, "active"), margin: { top: 8, - bottom: 7 + bottom: 16 }, }, headingGroup: { margin: { top: 8, - bottom: 7 + bottom: 12 }, }, checkboxGroup: { - margin: { - top: 8, - bottom: 7 + border: border(layer, "variant"), + background: withOpacity(background(layer, "hovered"), 0.25), + cornerRadius: 4, + padding: { + left: 12, + top: 2, + bottom: 2 }, }, button: { background: background(layer), - border: border(layer, "default"), + border: border(layer, "active"), cornerRadius: 4, margin: { - top: 8, - bottom: 7 + top: 4, + bottom: 4 }, padding: { - top: 1, - bottom: 1, + top: 3, + bottom: 3, left: 7, right: 7, }, ...text(layer, "sans", "default", interactive_text_size), hover: { ...text(layer, "sans", "default", interactive_text_size), - background: background(layer, "default"), + background: background(layer, "hovered"), border: border(layer, "active"), }, }, @@ -81,7 +93,7 @@ export default function welcome(colorScheme: ColorScheme) { }, container: { margin: { - top: 5, + top: 4, }, }, width: 12, @@ -101,7 +113,7 @@ export default function welcome(colorScheme: ColorScheme) { hovered: { ...checkboxBase, background: background(layer, "hovered"), - border: border(layer, "hovered") + border: border(layer, "active") }, hoveredAndChecked: { ...checkboxBase, From f62e0b502ab20c77a5e8296e0853fcfcbf2e9faa Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Wed, 8 Mar 2023 12:12:27 -0800 Subject: [PATCH 42/93] Remove welcome experience action Make logo switch between light and dark co-authored-by: Nathan --- Cargo.lock | 1 + assets/images/zed-logo-90x90.png | Bin 12413 -> 0 bytes crates/project_panel/src/project_panel.rs | 2 +- crates/welcome/Cargo.toml | 1 + crates/welcome/src/welcome.rs | 25 ++++++++++++-- crates/zed/src/main.rs | 21 ++++++------ crates/zed/src/zed.rs | 29 +--------------- styles/src/styleTree/projectPanel.ts | 39 ++++++++-------------- 8 files changed, 51 insertions(+), 67 deletions(-) delete mode 100644 assets/images/zed-logo-90x90.png diff --git a/Cargo.lock b/Cargo.lock index 9d950712a894afe51c54611296e5c301645f2457..ac4cbb376150d43ac2c8dcae0dfa090f98920d98 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8029,6 +8029,7 @@ name = "welcome" version = "0.1.0" dependencies = [ "anyhow", + "db", "editor", "fuzzy", "gpui", diff --git a/assets/images/zed-logo-90x90.png b/assets/images/zed-logo-90x90.png deleted file mode 100644 index 17f92d2c1afbb8459fd31bfdc7ace50a412ce0a8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12413 zcmZ{K2UJthvUcbK0tyP!QKU%;5G2%qq9P(iKza!!v;dLNds7hU9i${k@6x4%C^hsF ziZp=$0i^f#)R72F8#@>P@G>+ZiA+m#jn;o!IEK4qcc*AV4ML7baKs)<>J$9SJV?=iDbt)KYzEuONsoZlqIlq7V-#d zsY1oPtmVj|mZI1n#t3_(D!6 z8X|uyi1-MKDU@s6dxmE;>C zc0pX`J@smE(jXZ-6!7F0?Nh~jABD``Cv(<(r2GD&F$VDPX6RGe7>kEgF&q>Y_bYDl zJ$V&FVIi#%!SXEffmO8fOKBwg+B46X+AfAWA;aq2w*LBPx;NrIPZWmkIg@@4?tij3 z_|*BXex!Eh*&yluO;3`h2v;<4$d_ea>)n)uc^YeE#NzMoj!NIO(r(t?(+THqf4gAo z*!NBQmx>|TpSyoR86U0Y_1vW!c_8=L!x-jQ<{1`se)Dg8ZBrdP9j6|vdb3|j2dED6 zOwh{QkaV(pZSv)|F89`f9c5sx{HQH^nku2({JJ+k1epp%SFdzKhY*#%o_T8dj@ zUSit?JWn@M-9f+Cd>?-jKNg=JZ`t$s6&U7U_@p}9^No2v<7mz((pK<5=HT{0`lnBy zLO(UU%KoIwWs+mK?BDY|K{a7OOyx6GgmS8?=AibF>xk;epOM+2HD}6tplqm6UfCC& zk%3{*SSeoAIjU~_CLq-x9BkI_mv z5~M2T@blZ0Be=t7l(B5Fh;x{4ykMlRWbb)W4l_Enph3I#%~3g<@xTk92BLIUyJ^p} ztOL~P70D0|Wb?B=C-Tvndm;DAFW{2;qUiL3G??@WsYZ|rsTGwmqb>6(ljXfqu#C+F z{D<(aI4yGtSPHfunDg`Z*9zU`Vy9w=xz8fh{KJmxqWB^KopPLR9ATVPTxYJ9W{pkZ zn&$}p2n57g$!AH~XNzG=*2GNW)^N;y27Pk+y81s11Zu6T+#L$cyDKr3#pT`>&ue$f zKbyaWx%7Uv?yKpqnlyv#Pbjy2y7Rz?1<{|dI_0olunt%!1zrL#OHDDTn6|8Ku;Z2vY>M?6 zN}vC;(){D%+nE)O4ozL>{U|xvO&O5vktYOYC#fgqv9crtqysi%UCXEuiEb4~1GB7< z4v07E5h|}axB2OuQL`)yT$R*{eWe-|gu;}~ZgFCR8a{eWv9GW%nQY9_qZw~8tKZ&! zIQURl@GJLMU>BG5lfgCU(|6X}Q}YcnL>c}%ee0BtlzMlNLhBnVA z(rHCuGx3U=eR;2P#e)?jfZj&Oi#K{dO5W~#5E^qkCLw0v3riOLi|QAkFILaDA}((& zGE_?8OpD(ZKd9kS6?E`4botfkesw&29Qi(!JdC#VA)f0KU25!0B}b)(*wZ|c*VDo! zUiH2EU)J0#b^DXSi^H#*QuIJ-7>(4QC>M#8Xckl>_=I0B&E)5n+Cq+<>KffU5@r(M zhvx4G-;HCE^0h|e@Co{#Pi6Y}?Tz#i^=h7ar~D#1hWCBrZl{$CE}C1q!#AP14>gevH47UamD4#j!w+maS)wGFar@m*VGYRWG)74kB)2$=(OX?UUv+1k z=ZZGY_cJs2Xj>-2Bi2J_Wg255(!v82-bx}lCJ7`Fq>Nw?GMcFSSZRG`X5rZLJCQ3_ znIg$~g=~3C@0HQ#x_vBRNZ@ebQSa}h#|%t&a15>&xAqlOVr*lISN|XfmZyDxT=8C( z+ke>mq{83KKp6&1l8BE_@HXPp^*G__MD_SF879;h+E=gROW+^j58;1`5A+)Hw6es? zs^By6E>!D!>tWcIIbnEvPK6R|T3iGCNZd6(BmrzMI$dQsg8j7rX*$6-!6o$oTsCp; z81}9=qNLdXUdw35KY6%pwKH&3LuQZ2ugHHi{p43n!{TKBxAc;huYLuyIkiO=*xH%c z8CI_^hiOHwMWwSvEp9GU`dRsFGhm;&gNw_vRNGD4TC5E=fyJNb6A_S_o4wJAcVE5N z^l)K{6Q?MS1>wV(qk~VVd?MB&SXDw*HWd{jYs9?7vFw#{HD}*;c6#Xad9+d483Hnr z?vJ*#u58xUbgYK^ovSgn9`51`8zoLLD^vX;87=Pjx4%zntF9M>88bwg?0$3J7d=BR z-o^4$=@^xcU*UJ*KB;hn_Q$nw73@qIxK_C%i6xRx!)~bAV*VcP}z`I&oO-vZ(X5vz4*t_sxI6 z72qI*PVJJc3pI#^-@RkqbETt^jDd}T5|iI8`!_KcuTJ$Z`%Vq^js~}) zNGr+6a=aP+-0!rSe#*@yY@DHzS0jc(LBuXoU9V*Yy1M*Yh1>jo$JBZ08WPxwfW(*_ z)reSHM<1}u_c1`N1wQSNj85tmWbJKj7egKfPqcg&le{JVV%ESgn&v7xM)DHqb2Snu zx<0qj0^ovBQnNNbeRy5N8p3pyELBthkFMz(0Ad1C0MRu?03f_R(f*4jxTbmk!w<0m z5dT950DxRy0RTcY;lDXmXrlkne}(TGBnPimYHYN0opn`SOPM3=g-k6FW-uXl`*(j8 z05a}U*Q7nn*_6ZG-p;{E%3b!sKQyGS>A!5?1CD>FIKyQh=&Go5C?Jq94sju2A>juQ z3Jwkq8Ki}!l*Y3c|AJrN$v&`lc77)X1iHDo3AurU5J)Sah@_+>P*@ZwDk^xbA?W1c z;B4wH=-|Zp&q4lcoM$j6bEM5XXB&hA$KP>H%@8imvJW2oHT3V}pME;qSpLV7gVVpl zx(*QdR{|6f5(fTnFqpf|{{j0e`6uijasAVr%-_MJ6cG0BkT55wYquaGGXF5}|MC9g z-aqv4DjE35<>Br0*eL!9vCS-d!pq|u$itBC7|bt%?nwuU#|HP z`xDkqUDu?DOaTg4noV!2wI0)17&rTuHwpKelJVaZy+^Jr`%;(w#t#93`>n(KA4!-O zQ$Cnjw2q{iSX}O2t}lgleZtR#$%8sd+WXPcA5rMla2kgY&^7V9ILP~Xu~#9- ze^y{;;ktF;qIBGyptL@rpAmQXIT_;x_r}%#&k9`#=G zpuBgxbv{Iv>M8Kb`#xfHg(=j!B+HkDjPnl|_zFp8`4AkOmA9)B)&ou|X^;6~auHna zi>EA0%yRgRMZuJA+PO)pJDqRTqX_H$PuSyI{i?Ei-fxwVrG7$Hs8m&TRaJFp_j;Oa={w;^|*eYMR;9^b*TdtkpmDiY&S0sEf ztzC^`ua+V|Gw+~}&dow9C?(gc1jjH()t%?rP@T9ltevV^vyZ}qE{wyDSd`Di{!BH? z2?jJimoXRs%rIgGC}wyCSjW?lB>|;xtW<%TkP=AVxz{wV{|98{bl@OWYCzMzDim=? zxP`xieVqFKNNcy;ep%lv+yskR7EE9Mya$ZrD`OcDP66*HF;vJ>HqM{L;;t@KHc8D6ioFQNAKbl+?UNt_#US}CvC=`UyW zh@PLME{KK9w0evGR4I2RB(ZLggr;tve9@~UK2HioPwm4%-MPQGzd{K~v>KRnLCYw% zi^HttPwi1w-0k)a>54pcjJVfms5M!%gYH?k6eXRU3iovQG%+`~`q!G&*3{aq_r2J& z(0#HIE$8+_XORWmR~58KKwyp$ky?@#`K}M=W*uIm!)zd1ZG}<1Pds3a{LanINC{;D z*0+^i4)srUt#Z!h_wQsfH>k}2CZ=$9WuJGtTic@hkd;2sy=Nj~j$8O~Kw!ztQ}3}q zX9edf2I;0xaZzD;ma!^zD(KJhZ9NWz%1N)G_9i)LJjOkSlPDZ)rV)Z8zk}I$^h@CG zkR{Cb(xwB@u;IWDt8fxW6AeWryJ6zu4ArE4D znUt4G=|DcaL`?D0mEg`3eyR~(^pO#1T!Q7cn$af*rP)zp3I|uvSI~0BmUwi*BdTf5 z+V2Kmz}JDt7!mO(Yn_z_>1xy+LtF%#xx7}%@5pS>|ITxrb7Pk`S_nKJZ3+-vP*6qB zTeuPMCt=PWQ(u-mjxCL;e7!QmGXU)OhaKDmC_ecY$)D@=F2jI$x zCMk69W+Q)JV`b*2-RNAlJAZ7{nqRpbnQhI|{b+KEq5{Ex6D1#+_rq6B?hbb9M9h+v zhTwnYve~j~_TqG3c`c_DN^6_r8%w;+J@lKa`*q@Nz@X%q2N&+F@GD z>WZvP!BV-2%=as`%somavAS*LOy-y7o_mHPspYuK5TFmp;GVn}prA%ydoIow5{n^F zQv8)suvTj|AnP=lFKMtcoLlDnx~vIoe^8U%QS=KVegiG*uVo-uw58-%swv7Qb#b_H zGHxiyp}Ndc8L_q!UOLvE_6_c1d>12jF;&JQ=e4=?;7?+RtFm3ypap`!476|)=97`M zu`t$#@iyK>P(;n$>UV#^lVl?BONYnC+*1{566@ou@Vx=BH|R$&K4E)-B~=5noa$Ng zojMe6f4rQjBu*WK5yHkBVmt=kZZ(Jv^L3B%cPd{xj;%=;eCDD9V1D|si=6btdViBK z-&(PR)Nr9!#I80T^4~C*4PVo-URYF`1b{*Ylm$-4LEof>od9#0l^*+L>lB+c>@GU>2`zdOeVOG%18RwJ^wGWLZC%(S!d0rTobnr)#sFM-*s_B$ zh!6vP@hfe$2~gkZG>sJF{tCc6qrBMH7OC0$X2K7aMyH zK`KmY;zf*u<;v`N=nE0g zX1XRU^Hfmrt0?GY#hsH4-L5uF!8F~uGE#7-WMIb{47%8R?JWdI-J{(8o?%CH^@gba zHB_etYRRFTsF3l=CZH@QHLh1m**hYD5a;uV?IS~L+D!VUbX>Pim<2aJTz?6BDSaOx;MIi+XN&N1n95phD)EQ&J2>SosX|xQqwrw;F2~j8uZ?LGo)4np;K1y}bb`as%i6E6LiCk7F7|jbwIOQ9RT<$(zN;H}d45+s*$G#$-r zxXSlQuTxle=_t=vVu!$<)YD$=H`{V>%?UiXTr5~Wk3f(La%$DGI}F#b zw3{&yEF-Y=RBatrgRhfqRu?Za#CSMy^Gs&}rW6|Q^qC$M>JcGqj2G8uHH=9xomeV) z&Ug9U+BgAx1^d1%y$imP&)}@oMAGx-7oA8GfzW1rg5AS`($$uG<(d6t6G($=(9=-| z0(}l81D}IIn6G>Dw{>7{X1}X~TGX_`PSLLF=~&hJ!8nr0m~by=2_85(e9-}(IyRBMv zWU$U8hvDWh`q#Myvk!)WGKz@z->cNU5J90z9)5rk7f zZhojD_&9uK&?UN!Ib9?GOlqlm(|UJhFz`lCU=PiwyATXYE3J^ZDN~J_U+gefv-yee zS>rCNzR~Z89-B?pvx7@jiThes8^I7sJIpz`SnCFrXkvEFUVkIIlkaoc)}4f)43c}N zr#InMHci@ptk8d_Zs=}3X>#|j-9(J`t?Y}x39>OWA+BSnz7k_iF{rm~dWn}#ZI<>W z#%TI*NAEOP3428n-@U+E4VHncBgOWz_K^4XX9ox38OwJ@=)MtRT)ul9OFGSH3KFF? zW>)ib^|$6|lIi=2z`wf&>Zzf=?^7qOD4=v&t0W>4rhM$#&8QRu<439?5ZXZ|yPtsN2sR#J0-R^? zvnuB(XVBTNPC&_w(_shINkxrIG38II{8axxGcW1ALFdHDlIHN>>OX}DfU;4>*xWrv zi}m|grXJ}hew>%eV}KqV>V5@T?Oj2SclA3#OoX57xAm^{PKozH?c8Z<^MuI*MAS@e zq)p3y;PWKq^Etj$8OY#wYJS+s9Dky*f9?%=+SWjdI^*%OgW9g~f&$3`$q8|J=~&AB zSHf{)A@3-Y`}VLDdn4wmyvlfmw>5v-)@#&|9tu|6aPE&@F{a2pKcy4MVcDH8PW%eLN`i+9bEMeG{ic4cHJA{2GQQwj-Fu z-)?~?`O~Xw?0H=3mtD~J=uM0Z>-4mH_=Kni^&iQ5$;Ingeg2k`_q!513(XZeA#e_q z^vKAB23yKKZ?uVlZzN`yQbI09=bl!&`f$UG<}UFK8T$#)elfUz%DIdfpfBn-vFQ9x zV&ZPJ&)|p6ns1qXg8rhC2VOxb=cA$spVAGY>6sSfJ2ZoV+f7T$*7ilKA%LzB(m(2@!(Bw)RRbNmR zdn+YPs}ITTLAZZmb3lPlJ zO%4^xc1IJpw2&_qjMrN$@%p2zcGPy;^;tB`COJ8j&|F;F>CG6jUxcEb8x!~tI|my_ zMm)Lg`Nblu!ETp;*-lW!rh@VOUCpHD#-~A^Z27Ve$BZ#E^e&SEdsaZ6RR5Yxg{})9 z&yT6nsRTI5$E#$6hEurjWiF)b@uR6X{5*Kk4uZ|lj|aKIomW7Jzv>fNe!UeZ=eWA=g9;L(Binr8!3Wc*Va4^At;97pI+KB)m~ zc!;~NJcu$W0&ZZ1;BgEYun2ufL#B%`@ACZ-P9JAt5Rt{1a00x?eXzWWHM>2pW>jP` z4b<35|KrCR*?}ugjR?z5k7G}oK8ezD&OLl)zXDauD00CWOn)UEmBMM&)Pm#}p&a|B zI#$AGfE2Y|K2XtAaDS%qP`S5yH;V1`#EvEn?2Y0KivDsg{sKXnynxl6BwE>4yK&kY z94TlrQ5x1*EY)%vRPBx9520doM@orKu$!s)OAbi5ByQbZ)KMfe!$**(170MS`HZMR zeBxT}q#nxgJ#Kk)rpQlNmn|pQ;=e&4T)t+4HZ?HUoBl;8xlSef5bYxR^3|;xkp^G4 zCp@jM{X9qq-X2{v11wDV<&Y_LhD9)c zo+8wJRk9R=^3jywW!qeQAq+atXaO${b%1M4{Nn)hF9WgD`W_CmlD>KdSH&~~Y~u=Z zgLjh|acj`dJ);NA$v~CWAX$RG;=MfP>P-bL_WqSe2b4U^3ny{{XntXkIL*opAc416 z-#d*xUbM|fvPitTEcOQjP45Ba-Ir{?{tcYlG)d;Y>+yYa^jra#Nv37 zX1A+x@iM^S?}SLg(?3Vg&4t!Up;%RXS$(F%0uMBCU~VYM51wv$*#=ZPo>6!tk?PM^Ul<83+@1`^Vt_~ zD|OdkT68YC?_BUK=XgrBv_-E5Eeh6(W)3Q5H7euE@1{af@t$cV=}@y6b{83>tNN!* zC3y~CrvEmH(@zx zGM9{;z%hmtF8}D|gMdRr855Mq=()NDzJdNCz8ziaOpFn4$WCnUC#wBjo)?AeC<3wR zNlR@i9VD1Jov3%kcy11Q>z*!B4v4DiU1gIE&~RjBxGsXMPTRd+$P)r}$Kt|fV#lsL z%8!f>O=o4|WNH?G+Rb^`o1S}HNxe+hdD!l=bAe{?xD@QVOq-9HnbLf*Li7f8r-9N( zh^%l{!Y96Zy^K{#F>iqDv&TY75oB>}VNsmmYW)i!@iK-@ccG|mqwfogZj6I^aH&de*iy|3X1v_#dhPN%CYD75 zvbLnnSCSqZr#Z&yhx+0Od$8hZUfCsnqv=qmqrbE*bH*F@Cin~8w=Mx^#-d^q93$cH zAc+kJuO40J(*p2M_Ack_LrVMfFpUY{S0G?L6EwG(Dr(2$hIjOgCUR$3nR_+&)jHNp*1MA&UBW9I)pc;r$5R`0k{4BZ zswM^EFmrT4kWONacQuzTCPB(w{K_F~JT7R?^K|+{X;ZOa&Y?}q1b-(Lw4dNa7+x6V zKUNCit4WkSn7YV%ya>-Q)z?Yg=@}gDrt8%RW*=G8oKENq3P<3}$0*t5O^x{+S7qZM zJ-Cjjh)chuiy~NAbulbzG{(=;>$d!L4IYAJiYLO!AA87~kB*65j95}R3-HN^jB4`y zO!QV}8_9H=jJqQ%6Lwy}9^V-?YQ>I^voz%AX%?{WA=`9{&Z1lOKhf#gylDgv+k~BeJUc*xOpL!N*K_Zv1?3466Dy z8I{Hu#nvJxbfyT~^Sg08lMrC|DouNa5}9$f^o2zQCHw;9+<$BXs=gh zsHA7Ih+n=RwM@CO?$>i0dRS!M|7*m}t1lT;-WNi?v>ARg^1M3)`oiy!y_>p6`ETze z($}TD;GGXxSWU&Ia+$a_9DP@AqKPF(0rOiY@>@y>F(pKxF~Fm3P#k;xtxGkhlAfJl zL+175s0_A}TC#V(SW)%Yp)>)86DT(-D4853dbU`1&mQYS7 z9H1lYWk9F7xXUAvUP6cienPSbzox~%aXlk_=PZ_L`iGc;`pS6cVtN5co#}wthMsg< zft{6hOYgbDOd7<6O{D7t|A+-}CSUo!ai?4{aY3C2wq2fC`3v>rRm>&G)(8w%tdv!a zMP7~8TYz0Lz=LjP9Zes!H;jK>rx%|ic*bR9U$$KSORy!e-+eXNC)C))2B+rR1F>w# zUP(V$>BU)&GxSs<3)EQ8*|W{w37IgO(Bo`wLA+g9e(Jq96Nj4ekuT+0PsP>}IR7b6 zV+7-he0y}5T^hMWRnNH6eSRxuC_5exl!TNWrAHZHiuY5l-#9xOe>NTA>mr8?-SW>fk;zc!n&1?I7 zKCHM;=5!Q^uVyTwDztx%t(cY;+2+gQ-K%ghX66_-tm8F2rDjk> zE&eqxs=TY1eoSt28-JBWSk+nK=(Ic-i}j^iMlZ#F#+GUPZTPT44pfZ#q+jl@p-#15 zPsL#wj1INVtTlnpP4;@0N>Ad;SH342aEwCu+UbH2O%-6f@x;hFk=dglWc95=dz-PH}X2FL5v zso+P&*_%r}ys$Ty^VL7^c5H*)P05p~QkBA{=iMe}_ZuRH6h9fyV$=8gn&YsFg?)yr z%blJe@d6JG9t31*$-vb`V;855(rS>hort<)U?gq7ZBqvOJ;XRt7*n%P7WcTT{Q4E+ z7`yBWxnQa=AV?4Sl3y{(e3zNB$w2RwQ^#7ImRvz|b(*K$K_OY_Ome+3YZ1y534;uv zRSW%CQKurzkd(ZiMU{T$qY6$2%ITNGBC@Uwkh*XsS(nj8ev}qEmvuG=A((Y_{Q&so z5PaI5d?dGgT*d3FEADJJnIF`qc1g>+_gJ-|LaXVHY%1vZLl!kVz2~M&#{O7tDOc_8 zs7pkiD}RXRg+2to&2^QGz}fCp3we!^!eCVEMbhpvM{lh9F>Pt0ic{gBS}pdyu~Q7s z6_7I7ulN0MC3C&R&efaA^>^9a-B0VYRgL|8^qnzz9}$~hOLU7Exe*? zIj@f`KJ&PCe;nJ{SkQ?ZF1`7@vrhDd@h5hEnEMg*W`plkLS?hK+44cr-q>}+8scp` zDZ^OSKRsnQtbaA259L-`zpiNBr1@3<8kIBHXfWrZ;mYY|dg-#*qb^>qS#JgryikAW zhqPWj2zZ>wIvwjFB^hBgiGKDV@Tj4>b_S;l*?P!8fz%IEHFg(^ zm$JyI;>lfw6{fHu)d)-uWN~y2ZgN#}@6x7iVbWPQMKD(4bXq=aY+@pTk+}0D8(%RI*J~{vZ3keWzBIJX13$QJd7g$ehp{AC~i3 z&N*F|ekkFa4?;}E@+4ii&U3EI(Yi{W#q1wkD34JEy%aLZgR7>lt41iTyqZwZi*$hRI~_R>ox+>?(i5&%|Hm>`3j(&)_rv WubU>a9)CZGQhKiXtn?`~@c#k#=|!0U diff --git a/crates/project_panel/src/project_panel.rs b/crates/project_panel/src/project_panel.rs index a95a8b2deb50f624a14b9ca5bdfa9700f603eb49..08a83fbc435fc34ce89641897f1ba71c0eba3564 100644 --- a/crates/project_panel/src/project_panel.rs +++ b/crates/project_panel/src/project_panel.rs @@ -1329,7 +1329,7 @@ impl View for ProjectPanel { keystroke_label( parent_view_id, - "Open project", + "Open a project", &button_style, context_menu_item.keystroke, workspace::Open, diff --git a/crates/welcome/Cargo.toml b/crates/welcome/Cargo.toml index d3b0e09697ce74bf4c7610d98699fef180f27ab8..3da90deb2d1a2f1f6a9fdbe761bb4edcc35f664e 100644 --- a/crates/welcome/Cargo.toml +++ b/crates/welcome/Cargo.toml @@ -16,6 +16,7 @@ log = "0.4" editor = { path = "../editor" } fuzzy = { path = "../fuzzy" } gpui = { path = "../gpui" } +db = { path = "../db" } install_cli = { path = "../install_cli" } project = { path = "../project" } settings = { path = "../settings" } diff --git a/crates/welcome/src/welcome.rs b/crates/welcome/src/welcome.rs index 246ff267171887ad11dbb802222663bbe289e91e..a2386b8d2806ed03ec21840cab2bf42bbf3fb3cd 100644 --- a/crates/welcome/src/welcome.rs +++ b/crates/welcome/src/welcome.rs @@ -1,7 +1,8 @@ mod base_keymap_picker; -use std::borrow::Cow; +use std::{borrow::Cow, sync::Arc}; +use db::kvp::KEY_VALUE_STORE; use gpui::{ elements::{Empty, Flex, Label, MouseEventHandler, ParentElement, Svg}, Action, Element, ElementBox, Entity, MouseButton, MutableAppContext, RenderContext, @@ -9,10 +10,15 @@ use gpui::{ }; use settings::{settings_file::SettingsFile, Settings, SettingsFileContent}; use theme::CheckboxStyle; -use workspace::{item::Item, PaneBackdrop, Welcome, Workspace, WorkspaceId}; +use workspace::{ + item::Item, open_new, sidebar::SidebarSide, AppState, PaneBackdrop, Welcome, Workspace, + WorkspaceId, +}; use crate::base_keymap_picker::ToggleBaseKeymapSelector; +pub const FIRST_OPEN: &str = "first_open"; + pub fn init(cx: &mut MutableAppContext) { cx.add_action(|workspace: &mut Workspace, _: &Welcome, cx| { let welcome_page = cx.add_view(WelcomePage::new); @@ -22,6 +28,21 @@ pub fn init(cx: &mut MutableAppContext) { base_keymap_picker::init(cx); } +pub fn show_welcome_experience(app_state: &Arc, cx: &mut MutableAppContext) { + open_new(&app_state, cx, |workspace, cx| { + workspace.toggle_sidebar(SidebarSide::Left, cx); + let welcome_page = cx.add_view(|cx| WelcomePage::new(cx)); + workspace.add_item_to_center(Box::new(welcome_page.clone()), cx); + cx.focus(welcome_page); + cx.notify(); + }) + .detach(); + + db::write_and_log(cx, || { + KEY_VALUE_STORE.write_kvp(FIRST_OPEN.to_string(), "false".to_string()) + }); +} + pub struct WelcomePage { _settings_subscription: Subscription, } diff --git a/crates/zed/src/main.rs b/crates/zed/src/main.rs index 13a44fef106a4c357d3c888ec415b5878a66b4e0..9982b4114aabaeb13c1c41d066baf7a8a2f75919 100644 --- a/crates/zed/src/main.rs +++ b/crates/zed/src/main.rs @@ -36,6 +36,7 @@ use std::{ path::PathBuf, sync::Arc, thread, time::Duration, }; use terminal_view::{get_working_directory, TerminalView}; +use welcome::{show_welcome_experience, FIRST_OPEN}; use fs::RealFs; use settings::watched_json::WatchedJsonFile; @@ -46,10 +47,7 @@ use util::{channel::RELEASE_CHANNEL, paths, ResultExt, TryFutureExt}; use workspace::{ self, item::ItemHandle, notifications::NotifyResultExt, AppState, NewFile, OpenPaths, Workspace, }; -use zed::{ - self, build_window_options, initialize_workspace, languages, menus, WelcomeExperience, - FIRST_OPEN, -}; +use zed::{self, build_window_options, initialize_workspace, languages, menus}; fn main() { let http = http::client(); @@ -206,7 +204,7 @@ fn main() { cx.platform().activate(true); let paths = collect_path_args(); if paths.is_empty() { - cx.spawn(|cx| async move { restore_or_create_workspace(cx).await }) + cx.spawn(|cx| async move { restore_or_create_workspace(&app_state, cx).await }) .detach() } else { cx.dispatch_global_action(OpenPaths { paths }); @@ -219,8 +217,11 @@ fn main() { cx.update(|cx| workspace::open_paths(&paths, &app_state, None, cx)) .detach(); } else { - cx.spawn(|cx| async move { restore_or_create_workspace(cx).await }) - .detach() + cx.spawn({ + let app_state = app_state.clone(); + |cx| async move { restore_or_create_workspace(&app_state, cx).await } + }) + .detach() } cx.spawn(|cx| { @@ -259,7 +260,7 @@ fn main() { }); } -async fn restore_or_create_workspace(mut cx: AsyncAppContext) { +async fn restore_or_create_workspace(app_state: &Arc, mut cx: AsyncAppContext) { if let Some(location) = workspace::last_opened_workspace_paths().await { cx.update(|cx| { cx.dispatch_global_action(OpenPaths { @@ -267,9 +268,7 @@ async fn restore_or_create_workspace(mut cx: AsyncAppContext) { }) }); } else if matches!(KEY_VALUE_STORE.read_kvp(FIRST_OPEN), Ok(None)) { - cx.update(|cx| { - cx.dispatch_global_action(WelcomeExperience); - }); + cx.update(|cx| show_welcome_experience(app_state, cx)); } else { cx.update(|cx| { cx.dispatch_global_action(NewFile); diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index 3b48632265d5437f238bef5a19a48a6841f1cf14..3c093836f201146818b96ce1abaac6087a22fb14 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -8,7 +8,6 @@ use breadcrumbs::Breadcrumbs; pub use client; use collab_ui::{CollabTitlebarItem, ToggleContactsMenu}; use collections::VecDeque; -use db::kvp::KEY_VALUE_STORE; pub use editor; use editor::{Editor, MultiBuffer}; @@ -35,9 +34,7 @@ use std::{borrow::Cow, env, path::Path, str, sync::Arc}; use util::{channel::ReleaseChannel, paths, ResultExt, StaffMode}; use uuid::Uuid; pub use workspace; -use workspace::{open_new, sidebar::SidebarSide, AppState, Restart, Workspace}; - -pub const FIRST_OPEN: &str = "first_open"; +use workspace::{sidebar::SidebarSide, AppState, Restart, Workspace}; #[derive(Deserialize, Clone, PartialEq)] pub struct OpenBrowser { @@ -69,7 +66,6 @@ actions!( DecreaseBufferFontSize, ResetBufferFontSize, ResetDatabase, - WelcomeExperience ] ); @@ -258,29 +254,6 @@ pub fn init(app_state: &Arc, cx: &mut gpui::MutableAppContext) { workspace.toggle_sidebar_item_focus(SidebarSide::Left, 0, cx); }, ); - - cx.add_global_action({ - let app_state = app_state.clone(); - move |_: &WelcomeExperience, cx| { - if !matches!(KEY_VALUE_STORE.read_kvp(FIRST_OPEN), Ok(None)) { - return; //noop, in case someone fires this from the command palette - } - - open_new(&app_state, cx, |workspace, cx| { - workspace.toggle_sidebar(SidebarSide::Left, cx); - let welcome_page = cx.add_view(|cx| welcome::WelcomePage::new(cx)); - workspace.add_item_to_center(Box::new(welcome_page.clone()), cx); - cx.focus(welcome_page); - cx.notify(); - }) - .detach(); - - db::write_and_log(cx, || { - KEY_VALUE_STORE.write_kvp(FIRST_OPEN.to_string(), "false".to_string()) - }); - } - }); - activity_indicator::init(cx); call::init(app_state.client.clone(), app_state.user_store.clone(), cx); settings::KeymapFileContent::load_defaults(cx); diff --git a/styles/src/styleTree/projectPanel.ts b/styles/src/styleTree/projectPanel.ts index 2601a12691683c6e5dd85cdc5b99257c91d3165d..80cb884c4896de11d5c852468849b35787858508 100644 --- a/styles/src/styleTree/projectPanel.ts +++ b/styles/src/styleTree/projectPanel.ts @@ -30,37 +30,26 @@ export default function projectPanel(colorScheme: ColorScheme) { return { openProjectButton: { - ...text(layer, "mono", "active", { size: "sm" }), - background: background(layer, "on"), - cornerRadius: 6, - border: border(layer, "on"), + background: background(layer), + border: border(layer, "active"), + cornerRadius: 4, margin: { - top: 20, - left: 10, - right: 10 + top: 16, + left: 16, + right: 16, }, padding: { - bottom: 2, - left: 10, - right: 10, - top: 2, - }, - active: { - ...text(layer, "mono", "on", "inverted"), - background: background(layer, "on", "inverted"), - border: border(layer, "on", "inverted"), - }, - clicked: { - ...text(layer, "mono", "on", "pressed"), - background: background(layer, "on", "pressed"), - border: border(layer, "on", "pressed"), + top: 3, + bottom: 3, + left: 7, + right: 7, }, + ...text(layer, "sans", "default", { size: "sm" }), hover: { - ...text(layer, "mono", "on", "hovered"), - background: background(layer, "on", "hovered"), - border: border(layer, "on", "hovered"), + ...text(layer, "sans", "default", { size: "sm" }), + background: background(layer, "hovered"), + border: border(layer, "active"), }, - }, background: background(layer), padding: { left: 12, right: 12, top: 6, bottom: 6 }, From dad66eb3fbc7b981c7e433a3140571ced6cb42f6 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Wed, 8 Mar 2023 14:38:33 -0800 Subject: [PATCH 43/93] Make the workspace always open the dock --- crates/workspace/src/workspace.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index 1c1afea4aad2a58bc40a582053b0b08fa665213d..7c439522e8210878508f0a88a61a6a6c247e5ebe 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -742,6 +742,10 @@ impl Workspace { cx.defer(move |_, cx| { Self::load_from_serialized_workspace(weak_handle, serialized_workspace, cx) }); + } else { + if cx.global::().default_dock_anchor != DockAnchor::Expanded { + Dock::show(&mut this, false, cx); + } } this From 152755b04356cbb5d2990315fe81e5d57be08d23 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Wed, 8 Mar 2023 17:56:39 -0800 Subject: [PATCH 44/93] Add blank pane experience --- crates/collab/src/tests.rs | 11 +- crates/collab/src/tests/integration_tests.rs | 30 +--- crates/collab_ui/src/collab_ui.rs | 1 + crates/command_palette/src/command_palette.rs | 4 +- crates/diagnostics/src/diagnostics.rs | 10 +- crates/editor/src/editor_tests.rs | 20 +-- .../src/test/editor_lsp_test_context.rs | 12 +- crates/file_finder/src/file_finder.rs | 28 +--- crates/project_panel/src/project_panel.rs | 69 ++------- crates/terminal_view/src/terminal_view.rs | 10 +- crates/theme/src/theme.rs | 42 ++---- crates/theme/src/ui.rs | 119 +++++++++++++++ crates/welcome/src/welcome.rs | 142 ++++++++++-------- crates/workspace/src/dock.rs | 15 +- crates/workspace/src/pane.rs | 90 ++++++++--- crates/workspace/src/workspace.rs | 71 ++++++--- crates/zed/src/main.rs | 18 ++- crates/zed/src/zed.rs | 44 +----- styles/src/styleTree/contextMenu.ts | 9 +- styles/src/styleTree/welcome.ts | 20 ++- styles/src/styleTree/workspace.ts | 28 ++++ 21 files changed, 454 insertions(+), 339 deletions(-) create mode 100644 crates/theme/src/ui.rs diff --git a/crates/collab/src/tests.rs b/crates/collab/src/tests.rs index e9ffecf246d295934e15a2a3375af60f78a18c3e..8949b60993a041616d3d9381eadb65b2298b2488 100644 --- a/crates/collab/src/tests.rs +++ b/crates/collab/src/tests.rs @@ -198,6 +198,7 @@ impl TestServer { build_window_options: |_, _, _| Default::default(), initialize_workspace: |_, _, _| unimplemented!(), dock_default_item_factory: |_, _| unimplemented!(), + background_actions: || unimplemented!(), }); Project::init(&client); @@ -434,15 +435,7 @@ impl TestClient { cx: &mut TestAppContext, ) -> ViewHandle { let (_, root_view) = cx.add_window(|_| EmptyView); - cx.add_view(&root_view, |cx| { - Workspace::new( - Default::default(), - 0, - project.clone(), - |_, _| unimplemented!(), - cx, - ) - }) + cx.add_view(&root_view, |cx| Workspace::test_new(project.clone(), cx)) } fn create_new_root_dir(&mut self) -> PathBuf { diff --git a/crates/collab/src/tests/integration_tests.rs b/crates/collab/src/tests/integration_tests.rs index 1ab78ac310b0d23b10f08af62fbe8490f626161b..902242df012dd2428322447337a9794202333476 100644 --- a/crates/collab/src/tests/integration_tests.rs +++ b/crates/collab/src/tests/integration_tests.rs @@ -1449,15 +1449,7 @@ async fn test_host_disconnect( deterministic.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( - Default::default(), - 0, - project_b.clone(), - |_, _| unimplemented!(), - cx, - ) - }); + let (_, workspace_b) = cx_b.add_window(|cx| Workspace::test_new(project_b.clone(), cx)); let editor_b = workspace_b .update(cx_b, |workspace, cx| { workspace.open_path((worktree_id, "b.txt"), None, true, cx) @@ -4706,15 +4698,7 @@ async fn test_collaborating_with_code_actions( // Join the project as client B. let project_b = client_b.build_remote_project(project_id, cx_b).await; - let (_window_b, workspace_b) = cx_b.add_window(|cx| { - Workspace::new( - Default::default(), - 0, - project_b.clone(), - |_, _| unimplemented!(), - cx, - ) - }); + let (_window_b, workspace_b) = cx_b.add_window(|cx| Workspace::test_new(project_b.clone(), cx)); let editor_b = workspace_b .update(cx_b, |workspace, cx| { workspace.open_path((worktree_id, "main.rs"), None, true, cx) @@ -4937,15 +4921,7 @@ async fn test_collaborating_with_renames( .unwrap(); let project_b = client_b.build_remote_project(project_id, cx_b).await; - let (_window_b, workspace_b) = cx_b.add_window(|cx| { - Workspace::new( - Default::default(), - 0, - project_b.clone(), - |_, _| unimplemented!(), - cx, - ) - }); + let (_window_b, workspace_b) = cx_b.add_window(|cx| Workspace::test_new(project_b.clone(), cx)); let editor_b = workspace_b .update(cx_b, |workspace, cx| { workspace.open_path((worktree_id, "one.rs"), None, true, cx) diff --git a/crates/collab_ui/src/collab_ui.rs b/crates/collab_ui/src/collab_ui.rs index 6abfec21f74f0918e6338bc77a2e8aa8acfe783b..2dd2b0e6b47e9bbea6e2c916d201b70282517841 100644 --- a/crates/collab_ui/src/collab_ui.rs +++ b/crates/collab_ui/src/collab_ui.rs @@ -86,6 +86,7 @@ fn join_project(action: &JoinProject, app_state: Arc, cx: &mut Mutable 0, project, app_state.dock_default_item_factory, + app_state.background_actions, cx, ); (app_state.initialize_workspace)(&mut workspace, &app_state, cx); diff --git a/crates/command_palette/src/command_palette.rs b/crates/command_palette/src/command_palette.rs index 55522966fa48f1f25f402d999917144c0d884be1..52a0e1cdc0b15f62ef2a66da56f39ac0e2169a03 100644 --- a/crates/command_palette/src/command_palette.rs +++ b/crates/command_palette/src/command_palette.rs @@ -352,9 +352,7 @@ mod tests { }); let project = Project::test(app_state.fs.clone(), [], cx).await; - let (_, workspace) = cx.add_window(|cx| { - Workspace::new(Default::default(), 0, project, |_, _| unimplemented!(), cx) - }); + let (_, workspace) = cx.add_window(|cx| Workspace::test_new(project.clone(), cx)); let editor = cx.add_view(&workspace, |cx| { let mut editor = Editor::single_line(None, cx); editor.set_text("abc", cx); diff --git a/crates/diagnostics/src/diagnostics.rs b/crates/diagnostics/src/diagnostics.rs index e447a26c6b64159689dd6fc27b37d537507d7f21..223255544290ba93523a27ea5085f7871801e2a6 100644 --- a/crates/diagnostics/src/diagnostics.rs +++ b/crates/diagnostics/src/diagnostics.rs @@ -805,15 +805,7 @@ mod tests { .await; let project = Project::test(app_state.fs.clone(), ["/test".as_ref()], cx).await; - let (_, workspace) = cx.add_window(|cx| { - Workspace::new( - Default::default(), - 0, - project.clone(), - |_, _| unimplemented!(), - cx, - ) - }); + let (_, workspace) = cx.add_window(|cx| Workspace::test_new(project.clone(), cx)); // Create some diagnostics project.update(cx, |project, cx| { diff --git a/crates/editor/src/editor_tests.rs b/crates/editor/src/editor_tests.rs index 269390f72f14f7722230234579826a3ffaea7301..21cc9f889580f10d3ece2e2dfee7c18c203c37c4 100644 --- a/crates/editor/src/editor_tests.rs +++ b/crates/editor/src/editor_tests.rs @@ -484,7 +484,9 @@ fn test_navigation_history(cx: &mut gpui::MutableAppContext) { cx.set_global(Settings::test(cx)); cx.set_global(DragAndDrop::::default()); use workspace::item::Item; - let (_, pane) = cx.add_window(Default::default(), |cx| Pane::new(None, cx)); + let (_, pane) = cx.add_window(Default::default(), |cx| { + Pane::new(None, || unimplemented!(), cx) + }); let buffer = MultiBuffer::build_simple(&sample_text(300, 5, 'a'), cx); cx.add_view(&pane, |cx| { @@ -2354,10 +2356,10 @@ async fn test_clipboard(cx: &mut gpui::TestAppContext) { e.handle_input(") ", cx); }); cx.assert_editor_state(indoc! {" - ( one✅ - three - five ) ˇtwo one✅ four three six five ( one✅ - three + ( one✅ + three + five ) ˇtwo one✅ four three six five ( one✅ + three five ) ˇ"}); // Cut with three selections, one of which is full-line. @@ -5562,7 +5564,7 @@ async fn test_following_with_multiple_excerpts(cx: &mut gpui::TestAppContext) { Settings::test_async(cx); let fs = FakeFs::new(cx.background()); let project = Project::test(fs, ["/file.rs".as_ref()], cx).await; - let (_, pane) = cx.add_window(|cx| Pane::new(None, cx)); + let (_, pane) = cx.add_window(|cx| Pane::new(None, || unimplemented!(), cx)); let leader = pane.update(cx, |_, cx| { let multibuffer = cx.add_model(|_| MultiBuffer::new(0)); @@ -5831,11 +5833,11 @@ async fn go_to_hunk(deterministic: Arc, cx: &mut gpui::TestAppCon cx.assert_editor_state( &r#" ˇuse some::modified; - - + + fn main() { println!("hello there"); - + println!("around the"); println!("world"); } diff --git a/crates/editor/src/test/editor_lsp_test_context.rs b/crates/editor/src/test/editor_lsp_test_context.rs index 1b6d846e710f4ebd6f84c8053ab88d4c36294ef5..fe9a7909b8538bd7df4d91a97ff058d19cd1b3da 100644 --- a/crates/editor/src/test/editor_lsp_test_context.rs +++ b/crates/editor/src/test/editor_lsp_test_context.rs @@ -65,15 +65,7 @@ impl<'a> EditorLspTestContext<'a> { .insert_tree("/root", json!({ "dir": { file_name.clone(): "" }})) .await; - let (window_id, workspace) = cx.add_window(|cx| { - Workspace::new( - Default::default(), - 0, - project.clone(), - |_, _| unimplemented!(), - cx, - ) - }); + let (window_id, workspace) = cx.add_window(|cx| Workspace::test_new(project.clone(), cx)); project .update(cx, |project, cx| { project.find_or_create_local_worktree("/root", true, cx) @@ -134,7 +126,7 @@ impl<'a> EditorLspTestContext<'a> { (let_chain) (await_expression) ] @indent - + (_ "[" "]" @end) @indent (_ "<" ">" @end) @indent (_ "{" "}" @end) @indent diff --git a/crates/file_finder/src/file_finder.rs b/crates/file_finder/src/file_finder.rs index 273440dce253f54e8ccf5cb520bff321d403b1be..51d4df45f58fe59e32b4cc1eefbd10f9d49ddeaf 100644 --- a/crates/file_finder/src/file_finder.rs +++ b/crates/file_finder/src/file_finder.rs @@ -329,9 +329,7 @@ mod tests { .await; let project = Project::test(app_state.fs.clone(), ["/root".as_ref()], cx).await; - let (window_id, workspace) = cx.add_window(|cx| { - Workspace::new(Default::default(), 0, project, |_, _| unimplemented!(), cx) - }); + let (window_id, workspace) = cx.add_window(|cx| Workspace::test_new(project, cx)); cx.dispatch_action(window_id, Toggle); let finder = cx.read(|cx| workspace.read(cx).modal::().unwrap()); @@ -385,9 +383,7 @@ mod tests { .await; let project = Project::test(app_state.fs.clone(), ["/dir".as_ref()], cx).await; - let (_, workspace) = cx.add_window(|cx| { - Workspace::new(Default::default(), 0, project, |_, _| unimplemented!(), cx) - }); + let (_, workspace) = cx.add_window(|cx| Workspace::test_new(project, cx)); let (_, finder) = cx.add_window(|cx| FileFinder::new(workspace.read(cx).project().clone(), None, cx)); @@ -461,9 +457,7 @@ mod tests { cx, ) .await; - let (_, workspace) = cx.add_window(|cx| { - Workspace::new(Default::default(), 0, project, |_, _| unimplemented!(), cx) - }); + let (_, workspace) = cx.add_window(|cx| Workspace::test_new(project, cx)); let (_, finder) = cx.add_window(|cx| FileFinder::new(workspace.read(cx).project().clone(), None, cx)); finder @@ -487,9 +481,7 @@ mod tests { cx, ) .await; - let (_, workspace) = cx.add_window(|cx| { - Workspace::new(Default::default(), 0, project, |_, _| unimplemented!(), cx) - }); + let (_, workspace) = cx.add_window(|cx| Workspace::test_new(project, cx)); let (_, finder) = cx.add_window(|cx| FileFinder::new(workspace.read(cx).project().clone(), None, cx)); @@ -541,9 +533,7 @@ mod tests { cx, ) .await; - let (_, workspace) = cx.add_window(|cx| { - Workspace::new(Default::default(), 0, project, |_, _| unimplemented!(), cx) - }); + let (_, workspace) = cx.add_window(|cx| Workspace::test_new(project, cx)); let (_, finder) = cx.add_window(|cx| FileFinder::new(workspace.read(cx).project().clone(), None, cx)); @@ -585,9 +575,7 @@ mod tests { .await; let project = Project::test(app_state.fs.clone(), ["/root".as_ref()], cx).await; - let (_, workspace) = cx.add_window(|cx| { - Workspace::new(Default::default(), 0, project, |_, _| unimplemented!(), cx) - }); + let (_, workspace) = cx.add_window(|cx| Workspace::test_new(project, cx)); // When workspace has an active item, sort items which are closer to that item // first when they have the same name. In this case, b.txt is closer to dir2's a.txt @@ -624,9 +612,7 @@ mod tests { .await; let project = Project::test(app_state.fs.clone(), ["/root".as_ref()], cx).await; - let (_, workspace) = cx.add_window(|cx| { - Workspace::new(Default::default(), 0, project, |_, _| unimplemented!(), cx) - }); + let (_, workspace) = cx.add_window(|cx| Workspace::test_new(project, cx)); let (_, finder) = cx.add_window(|cx| FileFinder::new(workspace.read(cx).project().clone(), None, cx)); finder diff --git a/crates/project_panel/src/project_panel.rs b/crates/project_panel/src/project_panel.rs index 08a83fbc435fc34ce89641897f1ba71c0eba3564..079de79b1124b6064e7df9ca81e211147b2db1f0 100644 --- a/crates/project_panel/src/project_panel.rs +++ b/crates/project_panel/src/project_panel.rs @@ -6,15 +6,14 @@ use gpui::{ actions, anyhow::{anyhow, Result}, elements::{ - AnchorCorner, ChildView, ConstrainedBox, Container, ContainerStyle, Empty, Flex, - KeystrokeLabel, Label, MouseEventHandler, ParentElement, ScrollTarget, Stack, Svg, - UniformList, UniformListState, + AnchorCorner, ChildView, ConstrainedBox, ContainerStyle, Empty, Flex, Label, + MouseEventHandler, ParentElement, ScrollTarget, Stack, Svg, UniformList, UniformListState, }, geometry::vector::Vector2F, impl_internal_actions, keymap_matcher::KeymapContext, platform::CursorStyle, - Action, AppContext, ClipboardItem, Element, ElementBox, Entity, ModelHandle, MouseButton, + AppContext, ClipboardItem, Element, ElementBox, Entity, ModelHandle, MouseButton, MutableAppContext, PromptLevel, RenderContext, Task, View, ViewContext, ViewHandle, }; use menu::{Confirm, SelectNext, SelectPrev}; @@ -28,7 +27,7 @@ use std::{ path::{Path, PathBuf}, sync::Arc, }; -use theme::{ContainedText, ProjectPanelEntry}; +use theme::ProjectPanelEntry; use unicase::UniCase; use workspace::Workspace; @@ -1315,7 +1314,6 @@ impl View for ProjectPanel { .with_child(ChildView::new(&self.context_menu, cx).boxed()) .boxed() } else { - let parent_view_id = cx.handle().id(); Flex::column() .with_child( MouseEventHandler::::new(2, cx, { @@ -1327,12 +1325,11 @@ impl View for ProjectPanel { let context_menu_item = context_menu_item_style.style_for(state, true).clone(); - keystroke_label( - parent_view_id, + theme::ui::keystroke_label( "Open a project", &button_style, - context_menu_item.keystroke, - workspace::Open, + &context_menu_item.keystroke, + Box::new(workspace::Open), cx, ) .boxed() @@ -1357,38 +1354,6 @@ impl View for ProjectPanel { } } -fn keystroke_label( - view_id: usize, - label_text: &'static str, - label_style: &ContainedText, - keystroke_style: ContainedText, - action: A, - cx: &mut RenderContext, -) -> Container -where - A: Action, -{ - Flex::row() - .with_child( - Label::new(label_text, label_style.text.clone()) - .contained() - .boxed(), - ) - .with_child({ - KeystrokeLabel::new( - cx.window_id(), - view_id, - Box::new(action), - keystroke_style.container, - keystroke_style.text.clone(), - ) - .flex_float() - .boxed() - }) - .contained() - .with_style(label_style.container) -} - impl Entity for ProjectPanel { type Event = Event; } @@ -1474,15 +1439,7 @@ mod tests { .await; let project = Project::test(fs.clone(), ["/root1".as_ref(), "/root2".as_ref()], cx).await; - let (_, workspace) = cx.add_window(|cx| { - Workspace::new( - Default::default(), - 0, - project.clone(), - |_, _| unimplemented!(), - cx, - ) - }); + let (_, workspace) = cx.add_window(|cx| Workspace::test_new(project.clone(), cx)); let panel = workspace.update(cx, |_, cx| ProjectPanel::new(project, cx)); assert_eq!( visible_entries_as_strings(&panel, 0..50, cx), @@ -1574,15 +1531,7 @@ mod tests { .await; let project = Project::test(fs.clone(), ["/root1".as_ref(), "/root2".as_ref()], cx).await; - let (_, workspace) = cx.add_window(|cx| { - Workspace::new( - Default::default(), - 0, - project.clone(), - |_, _| unimplemented!(), - cx, - ) - }); + let (_, workspace) = cx.add_window(|cx| Workspace::test_new(project.clone(), cx)); let panel = workspace.update(cx, |_, cx| ProjectPanel::new(project, cx)); select_path(&panel, "root1", cx); diff --git a/crates/terminal_view/src/terminal_view.rs b/crates/terminal_view/src/terminal_view.rs index 3821185ec02e9d1981162863efa1a1708c9e3f97..110815e87027e7c018d3a25d6e7115c5b48b0be3 100644 --- a/crates/terminal_view/src/terminal_view.rs +++ b/crates/terminal_view/src/terminal_view.rs @@ -970,15 +970,7 @@ mod tests { let params = cx.update(AppState::test); let project = Project::test(params.fs.clone(), [], cx).await; - let (_, workspace) = cx.add_window(|cx| { - Workspace::new( - Default::default(), - 0, - project.clone(), - |_, _| unimplemented!(), - cx, - ) - }); + let (_, workspace) = cx.add_window(|cx| Workspace::test_new(project.clone(), cx)); (project, workspace) } diff --git a/crates/theme/src/theme.rs b/crates/theme/src/theme.rs index 13546b40cd958f6ff3c75513e4a9689aaa7526c1..524b7656268a1b143b0857075e2e43eaea17a9bc 100644 --- a/crates/theme/src/theme.rs +++ b/crates/theme/src/theme.rs @@ -9,6 +9,9 @@ use gpui::{ use serde::{de::DeserializeOwned, Deserialize}; use serde_json::Value; use std::{collections::HashMap, sync::Arc}; +use ui::{CheckboxStyle, IconStyle}; + +pub mod ui; pub use theme_registry::*; @@ -50,6 +53,7 @@ pub struct ThemeMeta { #[derive(Deserialize, Default)] pub struct Workspace { pub background: Color, + pub blank_pane: BlankPaneStyle, pub titlebar: Titlebar, pub tab_bar: TabBar, pub pane_divider: Border, @@ -69,6 +73,14 @@ pub struct Workspace { pub drop_target_overlay_color: Color, } +#[derive(Clone, Deserialize, Default)] +pub struct BlankPaneStyle { + pub logo: IconStyle, + pub keyboard_hints: ContainerStyle, + pub keyboard_hint: Interactive, + pub keyboard_hint_width: f32, +} + #[derive(Clone, Deserialize, Default)] pub struct Titlebar { #[serde(flatten)] @@ -858,46 +870,18 @@ pub struct WelcomeStyle { pub logo: IconStyle, pub logo_subheading: ContainedText, pub checkbox: CheckboxStyle, + pub checkbox_container: ContainerStyle, pub button: Interactive, pub button_group: ContainerStyle, pub heading_group: ContainerStyle, pub checkbox_group: ContainerStyle, } -#[derive(Clone, Deserialize, Default)] -pub struct IconStyle { - pub color: Color, - pub icon: String, - pub dimensions: Dimensions, -} - -#[derive(Clone, Deserialize, Default)] -pub struct Dimensions { - pub width: f32, - pub height: f32, -} - -#[derive(Clone, Deserialize, Default)] -pub struct CheckboxStyle { - pub check_icon: String, - pub check_icon_color: Color, - pub label: ContainedText, - pub container: ContainerStyle, - pub width: f32, - pub height: f32, - pub default: ContainerStyle, - pub checked: ContainerStyle, - pub hovered: ContainerStyle, - pub hovered_and_checked: ContainerStyle, -} - #[derive(Clone, Deserialize, Default)] pub struct ColorScheme { pub name: String, pub is_light: bool, - pub ramps: RampSet, - pub lowest: Layer, pub middle: Layer, pub highest: Layer, diff --git a/crates/theme/src/ui.rs b/crates/theme/src/ui.rs new file mode 100644 index 0000000000000000000000000000000000000000..ca71db37231531f1d76312807f55551a7b181c9b --- /dev/null +++ b/crates/theme/src/ui.rs @@ -0,0 +1,119 @@ +use gpui::{ + color::Color, + elements::{ + ConstrainedBox, Container, ContainerStyle, Empty, Flex, KeystrokeLabel, Label, + MouseEventHandler, ParentElement, Svg, + }, + Action, Element, EventContext, RenderContext, View, +}; +use serde::Deserialize; + +use crate::ContainedText; + +#[derive(Clone, Deserialize, Default)] +pub struct CheckboxStyle { + pub icon: IconStyle, + pub label: ContainedText, + pub default: ContainerStyle, + pub checked: ContainerStyle, + pub hovered: ContainerStyle, + pub hovered_and_checked: ContainerStyle, +} + +pub fn checkbox( + label: &'static str, + style: &CheckboxStyle, + checked: bool, + cx: &mut RenderContext, + change: fn(checked: bool, cx: &mut EventContext) -> (), +) -> MouseEventHandler { + MouseEventHandler::::new(0, cx, |state, _| { + let indicator = if checked { + icon(&style.icon) + } else { + Empty::new() + .constrained() + .with_width(style.icon.dimensions.width) + .with_height(style.icon.dimensions.height) + }; + + Flex::row() + .with_children([ + indicator + .contained() + .with_style(if checked { + if state.hovered() { + style.hovered_and_checked + } else { + style.checked + } + } else { + if state.hovered() { + style.hovered + } else { + style.default + } + }) + .boxed(), + Label::new(label, style.label.text.clone()) + .contained() + .with_style(style.label.container) + .boxed(), + ]) + .align_children_center() + .boxed() + }) + .on_click(gpui::MouseButton::Left, move |_, cx| change(!checked, cx)) + .with_cursor_style(gpui::CursorStyle::PointingHand) +} + +#[derive(Clone, Deserialize, Default)] +pub struct IconStyle { + pub color: Color, + pub icon: String, + pub dimensions: Dimensions, +} + +#[derive(Clone, Deserialize, Default)] +pub struct Dimensions { + pub width: f32, + pub height: f32, +} + +pub fn icon(style: &IconStyle) -> ConstrainedBox { + Svg::new(style.icon.clone()) + .with_color(style.color) + .constrained() + .with_width(style.dimensions.width) + .with_height(style.dimensions.height) +} + +pub fn keystroke_label( + label_text: &'static str, + label_style: &ContainedText, + keystroke_style: &ContainedText, + action: Box, + cx: &mut RenderContext, +) -> Container { + // FIXME: Put the theme in it's own global so we can + // query the keystroke style on our own + Flex::row() + .with_child( + Label::new(label_text, label_style.text.clone()) + .contained() + .boxed(), + ) + .with_child({ + KeystrokeLabel::new( + cx.window_id(), + cx.handle().id(), + action, + keystroke_style.container, + keystroke_style.text.clone(), + ) + .flex_float() + .boxed() + }) + .contained() + .with_style(label_style.container) +} diff --git a/crates/welcome/src/welcome.rs b/crates/welcome/src/welcome.rs index a2386b8d2806ed03ec21840cab2bf42bbf3fb3cd..89f161a283fb46435b20a71cae60d69983625cc4 100644 --- a/crates/welcome/src/welcome.rs +++ b/crates/welcome/src/welcome.rs @@ -4,12 +4,12 @@ use std::{borrow::Cow, sync::Arc}; use db::kvp::KEY_VALUE_STORE; use gpui::{ - elements::{Empty, Flex, Label, MouseEventHandler, ParentElement, Svg}, + elements::{Flex, Label, MouseEventHandler, ParentElement}, Action, Element, ElementBox, Entity, MouseButton, MutableAppContext, RenderContext, Subscription, View, ViewContext, }; -use settings::{settings_file::SettingsFile, Settings, SettingsFileContent}; -use theme::CheckboxStyle; +use settings::{settings_file::SettingsFile, Settings}; + use workspace::{ item::Item, open_new, sidebar::SidebarSide, AppState, PaneBackdrop, Welcome, Workspace, WorkspaceId, @@ -77,11 +77,7 @@ impl View for WelcomePage { .with_children([ Flex::column() .with_children([ - Svg::new(theme.welcome.logo.icon.clone()) - .with_color(theme.welcome.logo.color) - .constrained() - .with_width(theme.welcome.logo.dimensions.width) - .with_height(theme.welcome.logo.dimensions.height) + theme::ui::icon(&theme.welcome.logo) .aligned() .contained() .aligned() @@ -128,20 +124,34 @@ impl View for WelcomePage { .boxed(), Flex::column() .with_children([ - self.render_settings_checkbox::( + theme::ui::checkbox::( "Do you want to send telemetry?", &theme.welcome.checkbox, metrics, cx, - |content, checked| content.telemetry.set_metrics(checked), - ), - self.render_settings_checkbox::( + |checked, cx| { + SettingsFile::update(cx, move |file| { + file.telemetry.set_metrics(checked) + }) + }, + ) + .contained() + .with_style(theme.welcome.checkbox_container) + .boxed(), + theme::ui::checkbox::( "Send crash reports", &theme.welcome.checkbox, diagnostics, cx, - |content, checked| content.telemetry.set_diagnostics(checked), - ), + |checked, cx| { + SettingsFile::update(cx, move |file| { + file.telemetry.set_diagnostics(checked) + }) + }, + ) + .contained() + .with_style(theme.welcome.checkbox_container) + .boxed(), ]) .contained() .with_style(theme.welcome.checkbox_group) @@ -204,59 +214,59 @@ impl WelcomePage { .boxed() } - fn render_settings_checkbox( - &self, - label: &'static str, - style: &CheckboxStyle, - checked: bool, - cx: &mut RenderContext, - set_value: fn(&mut SettingsFileContent, checked: bool) -> (), - ) -> ElementBox { - MouseEventHandler::::new(0, cx, |state, _| { - let indicator = if checked { - Svg::new(style.check_icon.clone()) - .with_color(style.check_icon_color) - .constrained() - } else { - Empty::new().constrained() - }; + // fn render_settings_checkbox( + // &self, + // label: &'static str, + // style: &CheckboxStyle, + // checked: bool, + // cx: &mut RenderContext, + // set_value: fn(&mut SettingsFileContent, checked: bool) -> (), + // ) -> ElementBox { + // MouseEventHandler::::new(0, cx, |state, _| { + // let indicator = if checked { + // Svg::new(style.check_icon.clone()) + // .with_color(style.check_icon_color) + // .constrained() + // } else { + // Empty::new().constrained() + // }; - Flex::row() - .with_children([ - indicator - .with_width(style.width) - .with_height(style.height) - .contained() - .with_style(if checked { - if state.hovered() { - style.hovered_and_checked - } else { - style.checked - } - } else { - if state.hovered() { - style.hovered - } else { - style.default - } - }) - .boxed(), - Label::new(label, style.label.text.clone()) - .contained() - .with_style(style.label.container) - .boxed(), - ]) - .align_children_center() - .boxed() - }) - .on_click(gpui::MouseButton::Left, move |_, cx| { - SettingsFile::update(cx, move |content| set_value(content, !checked)) - }) - .with_cursor_style(gpui::CursorStyle::PointingHand) - .contained() - .with_style(style.container) - .boxed() - } + // Flex::row() + // .with_children([ + // indicator + // .with_width(style.width) + // .with_height(style.height) + // .contained() + // .with_style(if checked { + // if state.hovered() { + // style.hovered_and_checked + // } else { + // style.checked + // } + // } else { + // if state.hovered() { + // style.hovered + // } else { + // style.default + // } + // }) + // .boxed(), + // Label::new(label, style.label.text.clone()) + // .contained() + // .with_style(style.label.container) + // .boxed(), + // ]) + // .align_children_center() + // .boxed() + // }) + // .on_click(gpui::MouseButton::Left, move |_, cx| { + // SettingsFile::update(cx, move |content| set_value(content, !checked)) + // }) + // .with_cursor_style(gpui::CursorStyle::PointingHand) + // .contained() + // .with_style(style.container) + // .boxed() + // } } impl Item for WelcomePage { diff --git a/crates/workspace/src/dock.rs b/crates/workspace/src/dock.rs index 4281c04649ee12ea7ee6e02ee89784ca4620d22c..f86a9db71acf1b9b09cb66fd8b30d4cde9708a08 100644 --- a/crates/workspace/src/dock.rs +++ b/crates/workspace/src/dock.rs @@ -13,7 +13,7 @@ use gpui::{ use settings::{DockAnchor, Settings}; use theme::Theme; -use crate::{sidebar::SidebarSide, ItemHandle, Pane, Workspace}; +use crate::{sidebar::SidebarSide, BackgroundActions, ItemHandle, Pane, Workspace}; pub use toggle_dock_button::ToggleDockButton; #[derive(PartialEq, Clone, Deserialize)] @@ -182,11 +182,12 @@ pub struct Dock { impl Dock { pub fn new( default_item_factory: DockDefaultItemFactory, + background_actions: BackgroundActions, cx: &mut ViewContext, ) -> Self { let position = DockPosition::Hidden(cx.global::().default_dock_anchor); - let pane = cx.add_view(|cx| Pane::new(Some(position.anchor()), cx)); + let pane = cx.add_view(|cx| Pane::new(Some(position.anchor()), background_actions, cx)); pane.update(cx, |pane, cx| { pane.set_active(false, cx); }); @@ -492,6 +493,7 @@ mod tests { 0, project.clone(), default_item_factory, + || unimplemented!(), cx, ) }); @@ -620,7 +622,14 @@ mod tests { cx.update(|cx| init(cx)); let project = Project::test(fs, [], cx).await; let (window_id, workspace) = cx.add_window(|cx| { - Workspace::new(Default::default(), 0, project, default_item_factory, cx) + Workspace::new( + Default::default(), + 0, + project, + default_item_factory, + || unimplemented!(), + cx, + ) }); workspace.update(cx, |workspace, cx| { diff --git a/crates/workspace/src/pane.rs b/crates/workspace/src/pane.rs index fe339969617c2214606a9a1dbb6937737ca495c9..7e0e6bbe01d22bc891b22a93a92154e3a843608c 100644 --- a/crates/workspace/src/pane.rs +++ b/crates/workspace/src/pane.rs @@ -110,6 +110,8 @@ impl_internal_actions!( const MAX_NAVIGATION_HISTORY_LEN: usize = 1024; +pub type BackgroundActions = fn() -> &'static [(&'static str, &'static dyn Action)]; + pub fn init(cx: &mut MutableAppContext) { cx.add_action(|pane: &mut Pane, action: &ActivateItem, cx| { pane.activate_item(action.0, true, true, cx); @@ -215,6 +217,7 @@ pub struct Pane { toolbar: ViewHandle, tab_bar_context_menu: ViewHandle, docked: Option, + background_actions: BackgroundActions, } pub struct ItemNavHistory { @@ -271,7 +274,11 @@ enum ItemType { } impl Pane { - pub fn new(docked: Option, cx: &mut ViewContext) -> Self { + pub fn new( + docked: Option, + background_actions: BackgroundActions, + cx: &mut ViewContext, + ) -> Self { let handle = cx.weak_handle(); let context_menu = cx.add_view(ContextMenu::new); Self { @@ -292,6 +299,7 @@ impl Pane { toolbar: cx.add_view(|_| Toolbar::new(handle)), tab_bar_context_menu: context_menu, docked, + background_actions, } } @@ -1415,6 +1423,64 @@ impl Pane { .flex(1., false) .boxed() } + + fn render_blank_pane(&mut self, theme: &Theme, cx: &mut RenderContext) -> ElementBox { + let background = theme.workspace.background; + let keystroke_style = &theme.context_menu.item; + let theme = &theme.workspace.blank_pane; + Stack::new() + .with_children([ + Empty::new() + .contained() + .with_background_color(background) + .boxed(), + Flex::column() + .align_children_center() + .with_children([ + theme::ui::icon(&theme.logo).aligned().boxed(), + Flex::column() + .with_children({ + enum KeyboardHint {} + let keyboard_hint = &theme.keyboard_hint; + (self.background_actions)().into_iter().enumerate().map( + move |(idx, (text, action))| { + let hint_action = action.boxed_clone(); + MouseEventHandler::::new( + idx, + cx, + move |state, cx| { + theme::ui::keystroke_label( + text, + &keyboard_hint.style_for(state, false), + &keystroke_style + .style_for(state, false) + .keystroke, + hint_action, + cx, + ) + .boxed() + }, + ) + .on_click(MouseButton::Left, move |_, cx| { + cx.dispatch_any_action(action.boxed_clone()) + }) + .with_cursor_style(CursorStyle::PointingHand) + .boxed() + }, + ) + }) + .contained() + .with_style(theme.keyboard_hints) + .constrained() + .with_max_width(theme.keyboard_hint_width) + .aligned() + .boxed(), + ]) + .aligned() + .boxed(), + ]) + .boxed() + } } impl Entity for Pane { @@ -1508,11 +1574,8 @@ impl View for Pane { enum EmptyPane {} let theme = cx.global::().theme.clone(); - dragged_item_receiver::(0, 0, false, None, cx, |_, _| { - Empty::new() - .contained() - .with_background_color(theme.workspace.background) - .boxed() + dragged_item_receiver::(0, 0, false, None, cx, |_, cx| { + self.render_blank_pane(&theme, cx) }) .on_down(MouseButton::Left, |_, cx| { cx.focus_parent_view(); @@ -1809,9 +1872,7 @@ mod tests { let fs = FakeFs::new(cx.background()); let project = Project::test(fs, None, cx).await; - let (_, workspace) = cx.add_window(|cx| { - Workspace::new(Default::default(), 0, project, |_, _| unimplemented!(), cx) - }); + let (_, workspace) = cx.add_window(|cx| Workspace::test_new(project.clone(), cx)); let pane = workspace.read_with(cx, |workspace, _| workspace.active_pane().clone()); // 1. Add with a destination index @@ -1899,9 +1960,7 @@ mod tests { let fs = FakeFs::new(cx.background()); let project = Project::test(fs, None, cx).await; - let (_, workspace) = cx.add_window(|cx| { - Workspace::new(Default::default(), 0, project, |_, _| unimplemented!(), cx) - }); + let (_, workspace) = cx.add_window(|cx| Workspace::test_new(project.clone(), cx)); let pane = workspace.read_with(cx, |workspace, _| workspace.active_pane().clone()); // 1. Add with a destination index @@ -1977,9 +2036,7 @@ mod tests { let fs = FakeFs::new(cx.background()); let project = Project::test(fs, None, cx).await; - let (_, workspace) = cx.add_window(|cx| { - Workspace::new(Default::default(), 0, project, |_, _| unimplemented!(), cx) - }); + let (_, workspace) = cx.add_window(|cx| Workspace::test_new(project.clone(), cx)); let pane = workspace.read_with(cx, |workspace, _| workspace.active_pane().clone()); // singleton view @@ -2088,8 +2145,7 @@ mod tests { let fs = FakeFs::new(cx.background()); let project = Project::test(fs, None, cx).await; - let (_, workspace) = - cx.add_window(|cx| Workspace::new(None, 0, project, |_, _| unimplemented!(), cx)); + let (_, workspace) = cx.add_window(|cx| Workspace::test_new(project.clone(), cx)); let pane = workspace.read_with(cx, |workspace, _| workspace.active_pane().clone()); add_labled_item(&workspace, &pane, "A", cx); diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index 7c439522e8210878508f0a88a61a6a6c247e5ebe..65335d8671069d5e93a7852acbc5bed87852763d 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -432,6 +432,7 @@ pub struct AppState { fn(Option, Option, &dyn Platform) -> WindowOptions<'static>, pub initialize_workspace: fn(&mut Workspace, &Arc, &mut ViewContext), pub dock_default_item_factory: DockDefaultItemFactory, + pub background_actions: BackgroundActions, } impl AppState { @@ -455,6 +456,7 @@ impl AppState { initialize_workspace: |_, _, _| {}, build_window_options: |_, _, _| Default::default(), dock_default_item_factory: |_, _| unimplemented!(), + background_actions: || unimplemented!(), }) } } @@ -542,6 +544,7 @@ pub struct Workspace { active_call: Option<(ModelHandle, Vec)>, leader_updates_tx: mpsc::UnboundedSender<(PeerId, proto::UpdateFollowers)>, database_id: WorkspaceId, + background_actions: BackgroundActions, _window_subscriptions: [Subscription; 3], _apply_leader_updates: Task>, _observe_current_user: Task<()>, @@ -572,6 +575,7 @@ impl Workspace { workspace_id: WorkspaceId, project: ModelHandle, dock_default_factory: DockDefaultItemFactory, + background_actions: BackgroundActions, cx: &mut ViewContext, ) -> Self { cx.observe(&project, |_, _, cx| cx.notify()).detach(); @@ -602,7 +606,7 @@ impl Workspace { }) .detach(); - let center_pane = cx.add_view(|cx| Pane::new(None, cx)); + let center_pane = cx.add_view(|cx| Pane::new(None, background_actions, cx)); let pane_id = center_pane.id(); cx.subscribe(¢er_pane, move |this, _, event, cx| { this.handle_pane_event(pane_id, event, cx) @@ -610,7 +614,7 @@ impl Workspace { .detach(); cx.focus(¢er_pane); cx.emit(Event::PaneAdded(center_pane.clone())); - let dock = Dock::new(dock_default_factory, cx); + let dock = Dock::new(dock_default_factory, background_actions, cx); let dock_pane = dock.pane().clone(); let fs = project.read(cx).fs().clone(); @@ -730,6 +734,7 @@ impl Workspace { window_edited: false, active_call, database_id: workspace_id, + background_actions, _observe_current_user, _apply_leader_updates, leader_updates_tx, @@ -818,6 +823,7 @@ impl Workspace { workspace_id, project_handle, app_state.dock_default_item_factory, + app_state.background_actions, cx, ); (app_state.initialize_workspace)(&mut workspace, &app_state, cx); @@ -1432,7 +1438,7 @@ impl Workspace { } fn add_pane(&mut self, cx: &mut ViewContext) -> ViewHandle { - let pane = cx.add_view(|cx| Pane::new(None, cx)); + let pane = cx.add_view(|cx| Pane::new(None, self.background_actions, cx)); let pane_id = pane.id(); cx.subscribe(&pane, move |this, _, event, cx| { this.handle_pane_event(pane_id, event, cx) @@ -2648,6 +2654,11 @@ impl Workspace { }) .detach(); } + + #[cfg(any(test, feature = "test-support"))] + pub fn test_new(project: ModelHandle, cx: &mut ViewContext) -> Self { + Self::new(None, 0, project, |_, _| None, || &[], cx) + } } fn notify_if_database_failed(workspace: &ViewHandle, cx: &mut AsyncAppContext) { @@ -2988,17 +2999,10 @@ mod tests { use super::*; use fs::FakeFs; - use gpui::{executor::Deterministic, TestAppContext, ViewContext}; + use gpui::{executor::Deterministic, TestAppContext}; use project::{Project, ProjectEntryId}; use serde_json::json; - pub fn default_item_factory( - _workspace: &mut Workspace, - _cx: &mut ViewContext, - ) -> Option> { - unimplemented!() - } - #[gpui::test] async fn test_tab_disambiguation(cx: &mut TestAppContext) { cx.foreground().forbid_parking(); @@ -3011,7 +3015,8 @@ mod tests { Default::default(), 0, project.clone(), - default_item_factory, + |_, _| unimplemented!(), + || unimplemented!(), cx, ) }); @@ -3083,7 +3088,8 @@ mod tests { Default::default(), 0, project.clone(), - default_item_factory, + |_, _| unimplemented!(), + || unimplemented!(), cx, ) }); @@ -3183,7 +3189,8 @@ mod tests { Default::default(), 0, project.clone(), - default_item_factory, + |_, _| unimplemented!(), + || unimplemented!(), cx, ) }); @@ -3222,7 +3229,14 @@ mod tests { let project = Project::test(fs, None, cx).await; let (window_id, workspace) = cx.add_window(|cx| { - Workspace::new(Default::default(), 0, project, default_item_factory, cx) + Workspace::new( + Default::default(), + 0, + project, + |_, _| unimplemented!(), + || unimplemented!(), + cx, + ) }); let item1 = cx.add_view(&workspace, |cx| { @@ -3331,7 +3345,14 @@ mod tests { let project = Project::test(fs, [], cx).await; let (window_id, workspace) = cx.add_window(|cx| { - Workspace::new(Default::default(), 0, project, default_item_factory, cx) + Workspace::new( + Default::default(), + 0, + project, + |_, _| unimplemented!(), + || unimplemented!(), + cx, + ) }); // Create several workspace items with single project entries, and two @@ -3440,7 +3461,14 @@ mod tests { let project = Project::test(fs, [], cx).await; let (window_id, workspace) = cx.add_window(|cx| { - Workspace::new(Default::default(), 0, project, default_item_factory, cx) + Workspace::new( + Default::default(), + 0, + project, + |_, _| unimplemented!(), + || unimplemented!(), + cx, + ) }); let item = cx.add_view(&workspace, |cx| { @@ -3559,7 +3587,14 @@ mod tests { let project = Project::test(fs, [], cx).await; let (_, workspace) = cx.add_window(|cx| { - Workspace::new(Default::default(), 0, project, default_item_factory, cx) + Workspace::new( + Default::default(), + 0, + project, + |_, _| unimplemented!(), + || unimplemented!(), + cx, + ) }); let item = cx.add_view(&workspace, |cx| { diff --git a/crates/zed/src/main.rs b/crates/zed/src/main.rs index 9982b4114aabaeb13c1c41d066baf7a8a2f75919..2e2026309fca0da28ca878e9e8592589b945bd79 100644 --- a/crates/zed/src/main.rs +++ b/crates/zed/src/main.rs @@ -18,7 +18,7 @@ use futures::{ channel::{mpsc, oneshot}, FutureExt, SinkExt, StreamExt, }; -use gpui::{App, AssetSource, AsyncAppContext, MutableAppContext, Task, ViewContext}; +use gpui::{Action, App, AssetSource, AsyncAppContext, MutableAppContext, Task, ViewContext}; use isahc::{config::Configurable, Request}; use language::LanguageRegistry; use log::LevelFilter; @@ -45,9 +45,10 @@ use theme::ThemeRegistry; use util::StaffMode; use util::{channel::RELEASE_CHANNEL, paths, ResultExt, TryFutureExt}; use workspace::{ - self, item::ItemHandle, notifications::NotifyResultExt, AppState, NewFile, OpenPaths, Workspace, + self, dock::FocusDock, item::ItemHandle, notifications::NotifyResultExt, AppState, NewFile, + OpenPaths, Workspace, }; -use zed::{self, build_window_options, initialize_workspace, languages, menus}; +use zed::{self, build_window_options, initialize_workspace, languages, menus, OpenSettings}; fn main() { let http = http::client(); @@ -186,6 +187,7 @@ fn main() { build_window_options, initialize_workspace, dock_default_item_factory, + background_actions, }); auto_update::init(http, client::ZED_SERVER_URL.clone(), cx); @@ -703,3 +705,13 @@ pub fn dock_default_item_factory( Some(Box::new(terminal_view)) } + +pub fn background_actions() -> &'static [(&'static str, &'static dyn Action)] { + &[ + ("Go to file", &file_finder::Toggle), + ("Open the command palette", &command_palette::Toggle), + ("Focus the dock", &FocusDock), + ("Open recent projects", &recent_projects::OpenRecent), + ("Change your settings", &OpenSettings), + ] +} diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index 3c093836f201146818b96ce1abaac6087a22fb14..ae9fcc9b31de91ebce468fb6c5809c5ed47cfd5f 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -889,9 +889,7 @@ mod tests { .await; let project = Project::test(app_state.fs.clone(), ["/root".as_ref()], cx).await; - let (_, workspace) = cx.add_window(|cx| { - Workspace::new(Default::default(), 0, project, |_, _| unimplemented!(), cx) - }); + let (_, workspace) = cx.add_window(|cx| Workspace::test_new(project, cx)); let entries = cx.read(|cx| workspace.file_project_paths(cx)); let file1 = entries[0].clone(); @@ -1010,9 +1008,7 @@ mod tests { .await; let project = Project::test(app_state.fs.clone(), ["/dir1".as_ref()], cx).await; - let (_, workspace) = cx.add_window(|cx| { - Workspace::new(Default::default(), 0, project, |_, _| unimplemented!(), cx) - }); + let (_, workspace) = cx.add_window(|cx| Workspace::test_new(project, cx)); // Open a file within an existing worktree. cx.update(|cx| { @@ -1171,9 +1167,7 @@ mod tests { .await; let project = Project::test(app_state.fs.clone(), ["/root".as_ref()], cx).await; - let (window_id, workspace) = cx.add_window(|cx| { - Workspace::new(Default::default(), 0, project, |_, _| unimplemented!(), cx) - }); + let (window_id, workspace) = cx.add_window(|cx| Workspace::test_new(project, cx)); // Open a file within an existing worktree. cx.update(|cx| { @@ -1215,9 +1209,7 @@ mod tests { let project = Project::test(app_state.fs.clone(), ["/root".as_ref()], cx).await; project.update(cx, |project, _| project.languages().add(rust_lang())); - let (window_id, workspace) = cx.add_window(|cx| { - Workspace::new(Default::default(), 0, project, |_, _| unimplemented!(), cx) - }); + let (window_id, workspace) = cx.add_window(|cx| Workspace::test_new(project, cx)); let worktree = cx.read(|cx| workspace.read(cx).worktrees(cx).next().unwrap()); // Create a new untitled buffer @@ -1306,9 +1298,7 @@ mod tests { let project = Project::test(app_state.fs.clone(), [], cx).await; project.update(cx, |project, _| project.languages().add(rust_lang())); - let (window_id, workspace) = cx.add_window(|cx| { - Workspace::new(Default::default(), 0, project, |_, _| unimplemented!(), cx) - }); + let (window_id, workspace) = cx.add_window(|cx| Workspace::test_new(project, cx)); // Create a new untitled buffer cx.dispatch_action(window_id, NewFile); @@ -1361,9 +1351,7 @@ mod tests { .await; let project = Project::test(app_state.fs.clone(), ["/root".as_ref()], cx).await; - let (window_id, workspace) = cx.add_window(|cx| { - Workspace::new(Default::default(), 0, project, |_, _| unimplemented!(), cx) - }); + let (window_id, workspace) = cx.add_window(|cx| Workspace::test_new(project, cx)); let entries = cx.read(|cx| workspace.file_project_paths(cx)); let file1 = entries[0].clone(); @@ -1437,15 +1425,7 @@ mod tests { .await; let project = Project::test(app_state.fs.clone(), ["/root".as_ref()], cx).await; - let (_, workspace) = cx.add_window(|cx| { - Workspace::new( - Default::default(), - 0, - project.clone(), - |_, _| unimplemented!(), - cx, - ) - }); + let (_, workspace) = cx.add_window(|cx| Workspace::test_new(project.clone(), cx)); let entries = cx.read(|cx| workspace.file_project_paths(cx)); let file1 = entries[0].clone(); @@ -1709,15 +1689,7 @@ mod tests { .await; let project = Project::test(app_state.fs.clone(), ["/root".as_ref()], cx).await; - let (_, workspace) = cx.add_window(|cx| { - Workspace::new( - Default::default(), - 0, - project.clone(), - |_, _| unimplemented!(), - cx, - ) - }); + let (_, workspace) = cx.add_window(|cx| Workspace::test_new(project, cx)); let pane = workspace.read_with(cx, |workspace, _| workspace.active_pane().clone()); let entries = cx.read(|cx| workspace.file_project_paths(cx)); diff --git a/styles/src/styleTree/contextMenu.ts b/styles/src/styleTree/contextMenu.ts index 30f44a63141a70edd01998057385dfcd7f15adfc..b4a21deba4a7d21c0372dc34ff204922cdcf5b1b 100644 --- a/styles/src/styleTree/contextMenu.ts +++ b/styles/src/styleTree/contextMenu.ts @@ -26,14 +26,19 @@ export default function contextMenu(colorScheme: ColorScheme) { hover: { background: background(layer, "hovered"), label: text(layer, "sans", "hovered", { size: "sm" }), + keystroke: { + ...text(layer, "sans", "hovered", { + size: "sm", + weight: "bold", + }), + padding: { left: 3, right: 3 }, + }, }, active: { background: background(layer, "active"), - label: text(layer, "sans", "active", { size: "sm" }), }, activeHover: { background: background(layer, "active"), - label: text(layer, "sans", "active", { size: "sm" }), }, }, separator: { diff --git a/styles/src/styleTree/welcome.ts b/styles/src/styleTree/welcome.ts index 137c6df11177f8fed9a156acc8b6a5a49d62017d..7c437f110ef49e67acea1dfe72fe102f26205a61 100644 --- a/styles/src/styleTree/welcome.ts +++ b/styles/src/styleTree/welcome.ts @@ -86,20 +86,24 @@ export default function welcome(colorScheme: ColorScheme) { border: border(layer, "active"), }, }, + checkboxContainer: { + margin: { + top: 4, + }, + }, checkbox: { label: { ...text(layer, "sans", interactive_text_size), // Also supports margin, container, border, etc. }, - container: { - margin: { - top: 4, - }, + icon: { + color: foreground(layer, "on"), + icon: "icons/check_12.svg", + dimensions: { + width: 12, + height: 12, + } }, - width: 12, - height: 12, - checkIcon: "icons/check_12.svg", - checkIconColor: foreground(layer, "on"), default: { ...checkboxBase, background: background(layer, "default"), diff --git a/styles/src/styleTree/workspace.ts b/styles/src/styleTree/workspace.ts index c758e0227e2413ed86a15a10c28a22499d59131d..55b5c613410d1141b6a8e72c64aff2044c94cb51 100644 --- a/styles/src/styleTree/workspace.ts +++ b/styles/src/styleTree/workspace.ts @@ -41,6 +41,34 @@ export default function workspace(colorScheme: ColorScheme) { return { background: background(layer), + blankPane: { + logo: { + color: background(layer, "on"), + icon: "icons/logo_96.svg", + dimensions: { + width: 240, + height: 240, + } + }, + keyboardHints: { + margin: { + top: 32 + }, + padding: { + bottom: -8. + } + }, + keyboardHint: { + ...text(colorScheme.lowest, "sans", "variant", { size: "sm" }), + margin: { + bottom: 8 + }, + hover: { + ...text(colorScheme.lowest, "sans", "hovered", { size: "sm" }), + } + }, + keyboardHintWidth: 240, + }, joiningProjectAvatar: { cornerRadius: 40, width: 80, From cf6ea6d698e7bc3047e6a667f6e71c0889eb855c Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Wed, 8 Mar 2023 18:11:11 -0800 Subject: [PATCH 45/93] Fix bug with action keybindings not being resolved --- crates/editor/src/editor_tests.rs | 4 ++-- crates/theme/src/ui.rs | 22 ++++++++++++++++++++-- crates/workspace/src/dock.rs | 9 ++++++++- crates/workspace/src/pane.rs | 9 +++++++-- crates/workspace/src/workspace.rs | 6 ++++-- styles/src/styleTree/workspace.ts | 6 +++--- 6 files changed, 44 insertions(+), 12 deletions(-) diff --git a/crates/editor/src/editor_tests.rs b/crates/editor/src/editor_tests.rs index 21cc9f889580f10d3ece2e2dfee7c18c203c37c4..0176a1e01bd999b2786a9e84aa79d39340dce45b 100644 --- a/crates/editor/src/editor_tests.rs +++ b/crates/editor/src/editor_tests.rs @@ -485,7 +485,7 @@ fn test_navigation_history(cx: &mut gpui::MutableAppContext) { cx.set_global(DragAndDrop::::default()); use workspace::item::Item; let (_, pane) = cx.add_window(Default::default(), |cx| { - Pane::new(None, || unimplemented!(), cx) + Pane::new(0, None, || unimplemented!(), cx) }); let buffer = MultiBuffer::build_simple(&sample_text(300, 5, 'a'), cx); @@ -5564,7 +5564,7 @@ async fn test_following_with_multiple_excerpts(cx: &mut gpui::TestAppContext) { Settings::test_async(cx); let fs = FakeFs::new(cx.background()); let project = Project::test(fs, ["/file.rs".as_ref()], cx).await; - let (_, pane) = cx.add_window(|cx| Pane::new(None, || unimplemented!(), cx)); + let (_, pane) = cx.add_window(|cx| Pane::new(0, None, || unimplemented!(), cx)); let leader = pane.update(cx, |_, cx| { let multibuffer = cx.add_model(|_| MultiBuffer::new(0)); diff --git a/crates/theme/src/ui.rs b/crates/theme/src/ui.rs index ca71db37231531f1d76312807f55551a7b181c9b..5396265ad8fc0f5db41616a5acfd973e21c3ff70 100644 --- a/crates/theme/src/ui.rs +++ b/crates/theme/src/ui.rs @@ -97,6 +97,24 @@ pub fn keystroke_label( ) -> Container { // FIXME: Put the theme in it's own global so we can // query the keystroke style on our own + keystroke_label_for( + cx.window_id(), + cx.handle().id(), + label_text, + label_style, + keystroke_style, + action, + ) +} + +pub fn keystroke_label_for( + window_id: usize, + view_id: usize, + label_text: &'static str, + label_style: &ContainedText, + keystroke_style: &ContainedText, + action: Box, +) -> Container { Flex::row() .with_child( Label::new(label_text, label_style.text.clone()) @@ -105,8 +123,8 @@ pub fn keystroke_label( ) .with_child({ KeystrokeLabel::new( - cx.window_id(), - cx.handle().id(), + window_id, + view_id, action, keystroke_style.container, keystroke_style.text.clone(), diff --git a/crates/workspace/src/dock.rs b/crates/workspace/src/dock.rs index f86a9db71acf1b9b09cb66fd8b30d4cde9708a08..efba568b90458882d5d0d11e0250565dd2c1abca 100644 --- a/crates/workspace/src/dock.rs +++ b/crates/workspace/src/dock.rs @@ -187,7 +187,14 @@ impl Dock { ) -> Self { let position = DockPosition::Hidden(cx.global::().default_dock_anchor); - let pane = cx.add_view(|cx| Pane::new(Some(position.anchor()), background_actions, cx)); + let pane = cx.add_view(|cx| { + Pane::new( + cx.handle().id(), + Some(position.anchor()), + background_actions, + cx, + ) + }); pane.update(cx, |pane, cx| { pane.set_active(false, cx); }); diff --git a/crates/workspace/src/pane.rs b/crates/workspace/src/pane.rs index 7e0e6bbe01d22bc891b22a93a92154e3a843608c..abd410d875969a7d12611bae8d8e760ed9ade00e 100644 --- a/crates/workspace/src/pane.rs +++ b/crates/workspace/src/pane.rs @@ -218,6 +218,7 @@ pub struct Pane { tab_bar_context_menu: ViewHandle, docked: Option, background_actions: BackgroundActions, + workspace_id: usize, } pub struct ItemNavHistory { @@ -275,6 +276,7 @@ enum ItemType { impl Pane { pub fn new( + workspace_id: usize, docked: Option, background_actions: BackgroundActions, cx: &mut ViewContext, @@ -300,6 +302,7 @@ impl Pane { tab_bar_context_menu: context_menu, docked, background_actions, + workspace_id, } } @@ -1442,6 +1445,7 @@ impl Pane { .with_children({ enum KeyboardHint {} let keyboard_hint = &theme.keyboard_hint; + let workspace_id = self.workspace_id; (self.background_actions)().into_iter().enumerate().map( move |(idx, (text, action))| { let hint_action = action.boxed_clone(); @@ -1449,14 +1453,15 @@ impl Pane { idx, cx, move |state, cx| { - theme::ui::keystroke_label( + theme::ui::keystroke_label_for( + cx.window_id(), + workspace_id, text, &keyboard_hint.style_for(state, false), &keystroke_style .style_for(state, false) .keystroke, hint_action, - cx, ) .boxed() }, diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index 65335d8671069d5e93a7852acbc5bed87852763d..40053b103a4341952c2a263f04b99e6be958616a 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -606,7 +606,9 @@ impl Workspace { }) .detach(); - let center_pane = cx.add_view(|cx| Pane::new(None, background_actions, cx)); + let workspace_view_id = cx.handle().id(); + let center_pane = + cx.add_view(|cx| Pane::new(workspace_view_id, None, background_actions, cx)); let pane_id = center_pane.id(); cx.subscribe(¢er_pane, move |this, _, event, cx| { this.handle_pane_event(pane_id, event, cx) @@ -1438,7 +1440,7 @@ impl Workspace { } fn add_pane(&mut self, cx: &mut ViewContext) -> ViewHandle { - let pane = cx.add_view(|cx| Pane::new(None, self.background_actions, cx)); + let pane = cx.add_view(|cx| Pane::new(cx.handle().id(), None, self.background_actions, cx)); let pane_id = pane.id(); cx.subscribe(&pane, move |this, _, event, cx| { this.handle_pane_event(pane_id, event, cx) diff --git a/styles/src/styleTree/workspace.ts b/styles/src/styleTree/workspace.ts index 55b5c613410d1141b6a8e72c64aff2044c94cb51..cb99572853e1859d61dc4fde37b1e96d2faf0def 100644 --- a/styles/src/styleTree/workspace.ts +++ b/styles/src/styleTree/workspace.ts @@ -46,8 +46,8 @@ export default function workspace(colorScheme: ColorScheme) { color: background(layer, "on"), icon: "icons/logo_96.svg", dimensions: { - width: 240, - height: 240, + width: 256, + height: 256, } }, keyboardHints: { @@ -67,7 +67,7 @@ export default function workspace(colorScheme: ColorScheme) { ...text(colorScheme.lowest, "sans", "hovered", { size: "sm" }), } }, - keyboardHintWidth: 240, + keyboardHintWidth: 256, }, joiningProjectAvatar: { cornerRadius: 40, From a65dd0fd98b26d3eaa349c25e6e1d35a418ee720 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Wed, 8 Mar 2023 18:15:29 -0800 Subject: [PATCH 46/93] Restore correct checkbox text --- crates/welcome/src/welcome.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/welcome/src/welcome.rs b/crates/welcome/src/welcome.rs index 89f161a283fb46435b20a71cae60d69983625cc4..a1045ea1e8d9d20fe5ddd1ab35f4354f87cba509 100644 --- a/crates/welcome/src/welcome.rs +++ b/crates/welcome/src/welcome.rs @@ -125,7 +125,7 @@ impl View for WelcomePage { Flex::column() .with_children([ theme::ui::checkbox::( - "Do you want to send telemetry?", + "Send anonymous usage data to improve Zed (View what we're sending via Help > View Telemetry Log)", &theme.welcome.checkbox, metrics, cx, From 981b3a459f2d204c3daf23b6883328d7c8c26ecf Mon Sep 17 00:00:00 2001 From: Julia Date: Wed, 8 Mar 2023 21:31:14 -0500 Subject: [PATCH 47/93] Sort collaborators in titlebar alphabetically instead of by replica id --- crates/collab_ui/src/collab_titlebar_item.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/crates/collab_ui/src/collab_titlebar_item.rs b/crates/collab_ui/src/collab_titlebar_item.rs index f9f5738ad26762dd9e4fc5c08c6cf48439b90e67..c838f6a55fc3ec716571a9261066473910a6f413 100644 --- a/crates/collab_ui/src/collab_titlebar_item.rs +++ b/crates/collab_ui/src/collab_titlebar_item.rs @@ -572,15 +572,13 @@ impl CollabTitlebarItem { room: &ModelHandle, cx: &mut RenderContext, ) -> Vec { - let project = workspace.read(cx).project().read(cx); - let mut participants = room .read(cx) .remote_participants() .values() .cloned() .collect::>(); - participants.sort_by_key(|p| Some(project.collaborators().get(&p.peer_id)?.replica_id)); + participants.sort_by_cached_key(|p| p.user.github_login.clone()); participants .into_iter() From 943ea61452a6550bec95a23db5a006bff8b38ea2 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Wed, 8 Mar 2023 18:47:52 -0800 Subject: [PATCH 48/93] Add a note on how to check the telemetry --- crates/theme/src/theme.rs | 1 + crates/theme/src/ui.rs | 22 +++++++++++++++++----- crates/welcome/src/welcome.rs | 21 +++++++++++++++++++-- crates/zed/src/menus.rs | 2 +- styles/src/styleTree/welcome.ts | 9 +++++++++ 5 files changed, 47 insertions(+), 8 deletions(-) diff --git a/crates/theme/src/theme.rs b/crates/theme/src/theme.rs index 524b7656268a1b143b0857075e2e43eaea17a9bc..d331ca80a9fad31457fe648aaf7ae1b0e838d455 100644 --- a/crates/theme/src/theme.rs +++ b/crates/theme/src/theme.rs @@ -869,6 +869,7 @@ pub struct WelcomeStyle { pub page_width: f32, pub logo: IconStyle, pub logo_subheading: ContainedText, + pub usage_note: ContainedText, pub checkbox: CheckboxStyle, pub checkbox_container: ContainerStyle, pub button: Interactive, diff --git a/crates/theme/src/ui.rs b/crates/theme/src/ui.rs index 5396265ad8fc0f5db41616a5acfd973e21c3ff70..5441e711685970d3c33c9db94f9ac03815626531 100644 --- a/crates/theme/src/ui.rs +++ b/crates/theme/src/ui.rs @@ -4,7 +4,7 @@ use gpui::{ ConstrainedBox, Container, ContainerStyle, Empty, Flex, KeystrokeLabel, Label, MouseEventHandler, ParentElement, Svg, }, - Action, Element, EventContext, RenderContext, View, + Action, Element, ElementBox, EventContext, RenderContext, View, }; use serde::Deserialize; @@ -26,6 +26,21 @@ pub fn checkbox( checked: bool, cx: &mut RenderContext, change: fn(checked: bool, cx: &mut EventContext) -> (), +) -> MouseEventHandler { + let label = Label::new(label, style.label.text.clone()) + .contained() + .with_style(style.label.container) + .boxed(); + + checkbox_with_label(label, style, checked, cx, change) +} + +pub fn checkbox_with_label( + label: ElementBox, + style: &CheckboxStyle, + checked: bool, + cx: &mut RenderContext, + change: fn(checked: bool, cx: &mut EventContext) -> (), ) -> MouseEventHandler { MouseEventHandler::::new(0, cx, |state, _| { let indicator = if checked { @@ -55,10 +70,7 @@ pub fn checkbox( } }) .boxed(), - Label::new(label, style.label.text.clone()) - .contained() - .with_style(style.label.container) - .boxed(), + label, ]) .align_children_center() .boxed() diff --git a/crates/welcome/src/welcome.rs b/crates/welcome/src/welcome.rs index a1045ea1e8d9d20fe5ddd1ab35f4354f87cba509..3a35920b88922bb2b7bf13e5bd849acd77e4be3a 100644 --- a/crates/welcome/src/welcome.rs +++ b/crates/welcome/src/welcome.rs @@ -124,8 +124,25 @@ impl View for WelcomePage { .boxed(), Flex::column() .with_children([ - theme::ui::checkbox::( - "Send anonymous usage data to improve Zed (View what we're sending via Help > View Telemetry Log)", + theme::ui::checkbox_with_label::( + Flex::column() + .with_children([ + Label::new( + "Send anonymous usage data", + theme.welcome.checkbox.label.text.clone(), + ) + .contained() + .with_style(theme.welcome.checkbox.label.container) + .boxed(), + Label::new( + "Help > View Telemetry", + theme.welcome.usage_note.text.clone(), + ) + .contained() + .with_style(theme.welcome.usage_note.container) + .boxed(), + ]) + .boxed(), &theme.welcome.checkbox, metrics, cx, diff --git a/crates/zed/src/menus.rs b/crates/zed/src/menus.rs index 9381a909075b72364789e765600fd25885827f02..d5fb94b2b698aa8260fb9eab7bd5dee8c6af7b4c 100644 --- a/crates/zed/src/menus.rs +++ b/crates/zed/src/menus.rs @@ -137,7 +137,7 @@ pub fn menus() -> Vec> { items: vec![ MenuItem::action("Command Palette", command_palette::Toggle), MenuItem::separator(), - MenuItem::action("View Telemetry Log", crate::OpenTelemetryLog), + MenuItem::action("View Telemetry", crate::OpenTelemetryLog), MenuItem::action("View Dependency Licenses", crate::OpenLicenses), MenuItem::separator(), MenuItem::action( diff --git a/styles/src/styleTree/welcome.ts b/styles/src/styleTree/welcome.ts index 7c437f110ef49e67acea1dfe72fe102f26205a61..4ad3e51cd84545ef796b89d608996ad1aee0d872 100644 --- a/styles/src/styleTree/welcome.ts +++ b/styles/src/styleTree/welcome.ts @@ -86,10 +86,19 @@ export default function welcome(colorScheme: ColorScheme) { border: border(layer, "active"), }, }, + usageNote: { + ...text(layer, "sans", "variant", { size: "2xs" }), + margin: { + top: -4 + } + }, checkboxContainer: { margin: { top: 4, }, + padding: { + bottom: 8, + } }, checkbox: { label: { From 709c101834b5429c9ea580415e5e4e736e88384f Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Wed, 8 Mar 2023 18:50:17 -0800 Subject: [PATCH 49/93] Adjust styles on usage note --- styles/src/styleTree/welcome.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/styles/src/styleTree/welcome.ts b/styles/src/styleTree/welcome.ts index 4ad3e51cd84545ef796b89d608996ad1aee0d872..e1bd5c82bbac65595ed3e0cd60b1f5957158889c 100644 --- a/styles/src/styleTree/welcome.ts +++ b/styles/src/styleTree/welcome.ts @@ -88,8 +88,9 @@ export default function welcome(colorScheme: ColorScheme) { }, usageNote: { ...text(layer, "sans", "variant", { size: "2xs" }), - margin: { - top: -4 + padding: { + top: -4, + } }, checkboxContainer: { From 325827699e0942e05e250ff38a24c6ef4c71fbb2 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Wed, 8 Mar 2023 19:02:13 -0800 Subject: [PATCH 50/93] Adjust styling for blank page experience --- styles/src/styleTree/workspace.ts | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/styles/src/styleTree/workspace.ts b/styles/src/styleTree/workspace.ts index cb99572853e1859d61dc4fde37b1e96d2faf0def..d798a22e9d65b18140e3664b9cb7bb2858ee9569 100644 --- a/styles/src/styleTree/workspace.ts +++ b/styles/src/styleTree/workspace.ts @@ -40,34 +40,40 @@ export default function workspace(colorScheme: ColorScheme) { const followerAvatarOuterWidth = followerAvatarWidth + 4 return { - background: background(layer), + background: background(colorScheme.lowest), blankPane: { logo: { - color: background(layer, "on"), + color: border(layer, "active").color, icon: "icons/logo_96.svg", dimensions: { - width: 256, - height: 256, + width: 272, + height: 272, } }, keyboardHints: { margin: { - top: 32 + top: 32, + // bottom: -8. }, padding: { - bottom: -8. - } + top: 8, + left: 8, + right: 8, + }, + background: background(colorScheme.lowest), + border: border(layer, "active"), + cornerRadius: 4, }, keyboardHint: { - ...text(colorScheme.lowest, "sans", "variant", { size: "sm" }), + ...text(layer, "sans", "variant", { size: "sm" }), margin: { bottom: 8 }, hover: { - ...text(colorScheme.lowest, "sans", "hovered", { size: "sm" }), + ...text(layer, "sans", "hovered", { size: "sm" }), } }, - keyboardHintWidth: 256, + keyboardHintWidth: 272, }, joiningProjectAvatar: { cornerRadius: 40, From f626920af1a7f9337900618723c7c44129e30097 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Wed, 8 Mar 2023 19:03:44 -0800 Subject: [PATCH 51/93] Remove permanent Zed stateless --- crates/db/src/db.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/db/src/db.rs b/crates/db/src/db.rs index 989dcf0af561999fb31e108f712b92eb9ff499d3..ae9325ea2ea381d89b7e0cfddb48bc0cb22a0e16 100644 --- a/crates/db/src/db.rs +++ b/crates/db/src/db.rs @@ -42,7 +42,7 @@ const DB_FILE_NAME: &'static str = "db.sqlite"; lazy_static::lazy_static! { // !!!!!!! CHANGE BACK TO DEFAULT FALSE BEFORE SHIPPING - static ref ZED_STATELESS: bool = std::env::var("ZED_STATELESS").map_or(true, |v| !v.is_empty()); + static ref ZED_STATELESS: bool = std::env::var("ZED_STATELESS").map_or(false, |v| !v.is_empty()); static ref DB_FILE_OPERATIONS: Mutex<()> = Mutex::new(()); pub static ref BACKUP_DB_PATH: RwLock> = RwLock::new(None); pub static ref ALL_FILE_DB_FAILED: AtomicBool = AtomicBool::new(false); @@ -66,11 +66,11 @@ pub async fn open_db( let connection = async_iife!({ // Note: This still has a race condition where 1 set of migrations succeeds // (e.g. (Workspace, Editor)) and another fails (e.g. (Workspace, Terminal)) - // This will cause the first connection to have the database taken out + // This will cause the first connection to have the database taken out // from under it. This *should* be fine though. The second dabatase failure will // cause errors in the log and so should be observed by developers while writing // soon-to-be good migrations. If user databases are corrupted, we toss them out - // and try again from a blank. As long as running all migrations from start to end + // and try again from a blank. As long as running all migrations from start to end // on a blank database is ok, this race condition will never be triggered. // // Basically: Don't ever push invalid migrations to stable or everyone will have @@ -88,7 +88,7 @@ pub async fn open_db( }; } - // Take a lock in the failure case so that we move the db once per process instead + // Take a lock in the failure case so that we move the db once per process instead // of potentially multiple times from different threads. This shouldn't happen in the // normal path let _lock = DB_FILE_OPERATIONS.lock(); From 4ce51c813841af211fb9b36284f4df4db6078a53 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 9 Mar 2023 07:26:22 +0100 Subject: [PATCH 52/93] Limit dirty buffer save optimization to multi-buffers --- crates/editor/src/items.rs | 31 ++++++++++++++++++++++++++++--- crates/project/src/project.rs | 14 +------------- 2 files changed, 29 insertions(+), 16 deletions(-) diff --git a/crates/editor/src/items.rs b/crates/editor/src/items.rs index 0d594a66ef354ab49152a2e0e3d318592f6c3233..cda702de00f6411e10bda7ad890d8136688ebf42 100644 --- a/crates/editor/src/items.rs +++ b/crates/editor/src/items.rs @@ -612,9 +612,34 @@ impl Item for Editor { let buffers = self.buffer().clone().read(cx).all_buffers(); cx.as_mut().spawn(|mut cx| async move { format.await?; - project - .update(&mut cx, |project, cx| project.save_buffers(buffers, cx)) - .await?; + + if buffers.len() == 1 { + project + .update(&mut cx, |project, cx| project.save_buffers(buffers, cx)) + .await?; + } else { + // For multi-buffers, only save those ones that contain changes. For clean buffers + // we simulate saving by calling `Buffer::did_save`, so that language servers or + // other downstream listeners of save events get notified. + let (dirty_buffers, clean_buffers) = buffers.into_iter().partition(|buffer| { + buffer.read_with(&cx, |buffer, _| buffer.is_dirty() || buffer.has_conflict()) + }); + + project + .update(&mut cx, |project, cx| { + project.save_buffers(dirty_buffers, cx) + }) + .await?; + for buffer in clean_buffers { + buffer.update(&mut cx, |buffer, cx| { + let version = buffer.saved_version().clone(); + let fingerprint = buffer.saved_version_fingerprint(); + let mtime = buffer.saved_mtime(); + buffer.did_save(version, fingerprint, mtime, cx); + }); + } + } + Ok(()) }) } diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index f93de8e1d847d263dad2526dbcaaa77b0571b118..2ebea8d07dad811a378a065a7f666caaf594c6d3 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -1434,19 +1434,7 @@ impl Project { let worktree = file.worktree.clone(); let path = file.path.clone(); worktree.update(cx, |worktree, cx| match worktree { - Worktree::Local(worktree) => { - if buffer.read(cx).is_dirty() || buffer.read(cx).has_conflict() { - worktree.save_buffer(buffer, path, false, cx) - } else { - buffer.update(cx, |buffer, cx| { - let version = buffer.saved_version().clone(); - let fingerprint = buffer.saved_version_fingerprint(); - let mtime = buffer.saved_mtime(); - buffer.did_save(version.clone(), fingerprint, mtime, cx); - Task::ready(Ok((version, fingerprint, mtime))) - }) - } - } + Worktree::Local(worktree) => worktree.save_buffer(buffer, path, false, cx), Worktree::Remote(worktree) => worktree.save_buffer(buffer, cx), }) } From a00ce3f286db6ff34938abd4ceab6e9f08f27e28 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 9 Mar 2023 07:42:37 +0100 Subject: [PATCH 53/93] Add randomized test to remove active selections from buffer --- crates/language/src/buffer_tests.rs | 42 ++++++++++++++++------------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/crates/language/src/buffer_tests.rs b/crates/language/src/buffer_tests.rs index 0c375f0f4e1e27e59bbc737443307ae1b9c94c66..e98edbb2d32c1c6bf06a1f250e6ecb8b41a52b02 100644 --- a/crates/language/src/buffer_tests.rs +++ b/crates/language/src/buffer_tests.rs @@ -1804,25 +1804,31 @@ fn test_random_collaboration(cx: &mut MutableAppContext, mut rng: StdRng) { } 30..=39 if mutation_count != 0 => { buffer.update(cx, |buffer, cx| { - let mut selections = Vec::new(); - for id in 0..rng.gen_range(1..=5) { - let range = buffer.random_byte_range(0, &mut rng); - selections.push(Selection { - id, - start: buffer.anchor_before(range.start), - end: buffer.anchor_before(range.end), - reversed: false, - goal: SelectionGoal::None, - }); + if rng.gen_bool(0.2) { + log::info!("peer {} clearing active selections", replica_id); + active_selections.remove(&replica_id); + buffer.remove_active_selections(cx); + } else { + let mut selections = Vec::new(); + for id in 0..rng.gen_range(1..=5) { + let range = buffer.random_byte_range(0, &mut rng); + selections.push(Selection { + id, + start: buffer.anchor_before(range.start), + end: buffer.anchor_before(range.end), + reversed: false, + goal: SelectionGoal::None, + }); + } + let selections: Arc<[Selection]> = selections.into(); + log::info!( + "peer {} setting active selections: {:?}", + replica_id, + selections + ); + active_selections.insert(replica_id, selections.clone()); + buffer.set_active_selections(selections, false, Default::default(), cx); } - let selections: Arc<[Selection]> = selections.into(); - log::info!( - "peer {} setting active selections: {:?}", - replica_id, - selections - ); - active_selections.insert(replica_id, selections.clone()); - buffer.set_active_selections(selections, false, Default::default(), cx); }); mutation_count -= 1; } From 9328bb0153d5d8fbe58273a5f081ff68af1862da Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 9 Mar 2023 09:17:15 +0100 Subject: [PATCH 54/93] Introduce Kubernetes liveness probe to ensure database works --- crates/collab/k8s/manifest.template.yml | 7 +++++++ crates/collab/src/main.rs | 15 +++++++++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/crates/collab/k8s/manifest.template.yml b/crates/collab/k8s/manifest.template.yml index 339d02892ef2cf24f40815c3fd32dc0fb72c317a..b73070536f1d5d7104afc710cd57e42dba991650 100644 --- a/crates/collab/k8s/manifest.template.yml +++ b/crates/collab/k8s/manifest.template.yml @@ -59,6 +59,13 @@ spec: ports: - containerPort: 8080 protocol: TCP + livenessProbe: + httpGet: + path: /healthz + port: 8080 + initialDelaySeconds: 5 + periodSeconds: 5 + timeoutSeconds: 5 readinessProbe: httpGet: path: / diff --git a/crates/collab/src/main.rs b/crates/collab/src/main.rs index 0f783c13e58d3b64c0e034c18ea6173d63be4036..30ed35bc354ec74ea4e323f6ad85cc8d353c922d 100644 --- a/crates/collab/src/main.rs +++ b/crates/collab/src/main.rs @@ -1,11 +1,12 @@ use anyhow::anyhow; -use axum::{routing::get, Router}; +use axum::{routing::get, Extension, Router}; use collab::{db, env, executor::Executor, AppState, Config, MigrateConfig, Result}; use db::Database; use std::{ env::args, net::{SocketAddr, TcpListener}, path::Path, + sync::Arc, }; use tokio::signal::unix::SignalKind; use tracing_log::LogTracer; @@ -66,7 +67,12 @@ async fn main() -> Result<()> { let app = collab::api::routes(rpc_server.clone(), state.clone()) .merge(collab::rpc::routes(rpc_server.clone())) - .merge(Router::new().route("/", get(handle_root))); + .merge( + Router::new() + .route("/", get(handle_root)) + .route("/healthz", get(handle_liveness_probe)) + .layer(Extension(state.clone())), + ); axum::Server::from_tcp(listener)? .serve(app.into_make_service_with_connect_info::()) @@ -95,6 +101,11 @@ async fn handle_root() -> String { format!("collab v{VERSION}") } +async fn handle_liveness_probe(Extension(state): Extension>) -> Result { + state.db.get_all_users(0, 1).await?; + Ok("ok".to_string()) +} + pub fn init_tracing(config: &Config) -> Option<()> { use std::str::FromStr; use tracing_subscriber::layer::SubscriberExt; From 3daeabc1d6e2b58ee9c6e1793d2e8b72b97ed468 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 9 Mar 2023 09:30:04 +0100 Subject: [PATCH 55/93] collab 0.7.0 --- Cargo.lock | 2 +- crates/collab/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 82a045ed3a9b1d1608ddffe6952f449fd3c07de1..cfd27bbdd0afc23b68e26379a1c7fb09db56986c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1188,7 +1188,7 @@ dependencies = [ [[package]] name = "collab" -version = "0.6.2" +version = "0.7.0" dependencies = [ "anyhow", "async-tungstenite", diff --git a/crates/collab/Cargo.toml b/crates/collab/Cargo.toml index fee7089ce61853fc1104ec5ba3f6c062165d0695..a2ad7d73430f4bbd8a350e06e1de775f999c4880 100644 --- a/crates/collab/Cargo.toml +++ b/crates/collab/Cargo.toml @@ -3,7 +3,7 @@ authors = ["Nathan Sobo "] default-run = "collab" edition = "2021" name = "collab" -version = "0.6.2" +version = "0.7.0" publish = false [[bin]] From 9187863d0ef9ecf69e7d071b180700bd8dbcd3e8 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Thu, 9 Mar 2023 00:45:05 -0800 Subject: [PATCH 56/93] re-add spaces removed by new setting --- crates/collab/src/tests.rs | 4 +-- crates/editor/src/editor_tests.rs | 14 ++++----- crates/workspace/src/dock.rs | 4 +-- crates/workspace/src/workspace.rs | 52 +++++++------------------------ 4 files changed, 22 insertions(+), 52 deletions(-) diff --git a/crates/collab/src/tests.rs b/crates/collab/src/tests.rs index 8949b60993a041616d3d9381eadb65b2298b2488..80df0ed6dfb59136ad6183b0a0f42e34a5b63264 100644 --- a/crates/collab/src/tests.rs +++ b/crates/collab/src/tests.rs @@ -197,8 +197,8 @@ impl TestServer { fs: fs.clone(), build_window_options: |_, _, _| Default::default(), initialize_workspace: |_, _, _| unimplemented!(), - dock_default_item_factory: |_, _| unimplemented!(), - background_actions: || unimplemented!(), + dock_default_item_factory: |_, _| None, + background_actions: || &[], }); Project::init(&client); diff --git a/crates/editor/src/editor_tests.rs b/crates/editor/src/editor_tests.rs index 0176a1e01bd999b2786a9e84aa79d39340dce45b..d73c3c87db324aac0a47158c55bf10f705e48695 100644 --- a/crates/editor/src/editor_tests.rs +++ b/crates/editor/src/editor_tests.rs @@ -484,9 +484,7 @@ fn test_navigation_history(cx: &mut gpui::MutableAppContext) { cx.set_global(Settings::test(cx)); cx.set_global(DragAndDrop::::default()); use workspace::item::Item; - let (_, pane) = cx.add_window(Default::default(), |cx| { - Pane::new(0, None, || unimplemented!(), cx) - }); + let (_, pane) = cx.add_window(Default::default(), |cx| Pane::new(0, None, || &[], cx)); let buffer = MultiBuffer::build_simple(&sample_text(300, 5, 'a'), cx); cx.add_view(&pane, |cx| { @@ -2356,10 +2354,10 @@ async fn test_clipboard(cx: &mut gpui::TestAppContext) { e.handle_input(") ", cx); }); cx.assert_editor_state(indoc! {" - ( one✅ - three - five ) ˇtwo one✅ four three six five ( one✅ - three + ( one✅ + three + five ) ˇtwo one✅ four three six five ( one✅ + three five ) ˇ"}); // Cut with three selections, one of which is full-line. @@ -5564,7 +5562,7 @@ async fn test_following_with_multiple_excerpts(cx: &mut gpui::TestAppContext) { Settings::test_async(cx); let fs = FakeFs::new(cx.background()); let project = Project::test(fs, ["/file.rs".as_ref()], cx).await; - let (_, pane) = cx.add_window(|cx| Pane::new(0, None, || unimplemented!(), cx)); + let (_, pane) = cx.add_window(|cx| Pane::new(0, None, || &[], cx)); let leader = pane.update(cx, |_, cx| { let multibuffer = cx.add_model(|_| MultiBuffer::new(0)); diff --git a/crates/workspace/src/dock.rs b/crates/workspace/src/dock.rs index efba568b90458882d5d0d11e0250565dd2c1abca..fd7638c5fbb492296a28e051177a8fd9699f3014 100644 --- a/crates/workspace/src/dock.rs +++ b/crates/workspace/src/dock.rs @@ -500,7 +500,7 @@ mod tests { 0, project.clone(), default_item_factory, - || unimplemented!(), + || &[], cx, ) }); @@ -634,7 +634,7 @@ mod tests { 0, project, default_item_factory, - || unimplemented!(), + || &[], cx, ) }); diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index 40053b103a4341952c2a263f04b99e6be958616a..ef14bfa2fe090ed90b66f309789d9af632712c63 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -455,8 +455,8 @@ impl AppState { user_store, initialize_workspace: |_, _, _| {}, build_window_options: |_, _, _| Default::default(), - dock_default_item_factory: |_, _| unimplemented!(), - background_actions: || unimplemented!(), + dock_default_item_factory: |_, _| None, + background_actions: || &[], }) } } @@ -3017,8 +3017,8 @@ mod tests { Default::default(), 0, project.clone(), - |_, _| unimplemented!(), - || unimplemented!(), + |_, _| None, + || &[], cx, ) }); @@ -3090,8 +3090,8 @@ mod tests { Default::default(), 0, project.clone(), - |_, _| unimplemented!(), - || unimplemented!(), + |_, _| None, + || &[], cx, ) }); @@ -3191,8 +3191,8 @@ mod tests { Default::default(), 0, project.clone(), - |_, _| unimplemented!(), - || unimplemented!(), + |_, _| None, + || &[], cx, ) }); @@ -3231,14 +3231,7 @@ mod tests { let project = Project::test(fs, None, cx).await; let (window_id, workspace) = cx.add_window(|cx| { - Workspace::new( - Default::default(), - 0, - project, - |_, _| unimplemented!(), - || unimplemented!(), - cx, - ) + Workspace::new(Default::default(), 0, project, |_, _| None, || &[], cx) }); let item1 = cx.add_view(&workspace, |cx| { @@ -3347,14 +3340,7 @@ mod tests { let project = Project::test(fs, [], cx).await; let (window_id, workspace) = cx.add_window(|cx| { - Workspace::new( - Default::default(), - 0, - project, - |_, _| unimplemented!(), - || unimplemented!(), - cx, - ) + Workspace::new(Default::default(), 0, project, |_, _| None, || &[], cx) }); // Create several workspace items with single project entries, and two @@ -3463,14 +3449,7 @@ mod tests { let project = Project::test(fs, [], cx).await; let (window_id, workspace) = cx.add_window(|cx| { - Workspace::new( - Default::default(), - 0, - project, - |_, _| unimplemented!(), - || unimplemented!(), - cx, - ) + Workspace::new(Default::default(), 0, project, |_, _| None, || &[], cx) }); let item = cx.add_view(&workspace, |cx| { @@ -3589,14 +3568,7 @@ mod tests { let project = Project::test(fs, [], cx).await; let (_, workspace) = cx.add_window(|cx| { - Workspace::new( - Default::default(), - 0, - project, - |_, _| unimplemented!(), - || unimplemented!(), - cx, - ) + Workspace::new(Default::default(), 0, project, |_, _| None, || &[], cx) }); let item = cx.add_view(&workspace, |cx| { From 5bfd5e35b31ef046b7372e78cc3bca389bdf7b81 Mon Sep 17 00:00:00 2001 From: Nate Butler Date: Thu, 9 Mar 2023 10:47:01 -0500 Subject: [PATCH 57/93] Add light themes --- styles/src/themes/atelier-forest-light.ts | 55 +++++++++++++++++++++ styles/src/themes/atelier-heath-light.ts | 55 +++++++++++++++++++++ styles/src/themes/atelier-lakeside-light.ts | 55 +++++++++++++++++++++ styles/src/themes/atelier-plateau-light.ts | 55 +++++++++++++++++++++ styles/src/themes/atelier-savanna-light.ts | 55 +++++++++++++++++++++ styles/src/themes/atelier-seaside-dark.ts | 2 +- styles/src/themes/atelier-seaside-light.ts | 55 +++++++++++++++++++++ 7 files changed, 331 insertions(+), 1 deletion(-) create mode 100644 styles/src/themes/atelier-forest-light.ts create mode 100644 styles/src/themes/atelier-heath-light.ts create mode 100644 styles/src/themes/atelier-lakeside-light.ts create mode 100644 styles/src/themes/atelier-plateau-light.ts create mode 100644 styles/src/themes/atelier-savanna-light.ts create mode 100644 styles/src/themes/atelier-seaside-light.ts diff --git a/styles/src/themes/atelier-forest-light.ts b/styles/src/themes/atelier-forest-light.ts new file mode 100644 index 0000000000000000000000000000000000000000..ee9acd7ebb66c082ef39add429e44a41332507f0 --- /dev/null +++ b/styles/src/themes/atelier-forest-light.ts @@ -0,0 +1,55 @@ +import chroma from "chroma-js" +import { Meta } from "./common/colorScheme" +import { colorRamp, createColorScheme } from "./common/ramps" +import { metaCommon, name, buildSyntax, Variant } from "./common/atelier-common" + +const variant: Variant = { + meta: { + name: `${name} Forest Light`, + ...metaCommon, + url: "https://atelierbram.github.io/syntax-highlighting/atelier-schemes/forest/", + }, + colors: { + base00: "#f1efee", + base01: "#e6e2e0", + base02: "#a8a19f", + base03: "#9c9491", + base04: "#766e6b", + base05: "#68615e", + base06: "#2c2421", + base07: "#1b1918", + base08: "#f22c40", + base09: "#df5320", + base0A: "#c38418", + base0B: "#7b9726", + base0C: "#3d97b8", + base0D: "#407ee7", + base0E: "#6666ea", + base0F: "#c33ff3" + } +} + +const syntax = buildSyntax(variant) + +const theme = (variant: Variant) => { + const { meta, colors } = variant + + return createColorScheme(meta.name, true, { + neutral: chroma + .scale([ + colors.base00, colors.base01, colors.base02, colors.base03, colors.base04, colors.base05, colors.base06, colors.base07 + ].reverse()), + red: colorRamp(chroma(colors.base08)), + orange: colorRamp(chroma(colors.base09)), + yellow: colorRamp(chroma(colors.base0A)), + green: colorRamp(chroma(colors.base0B)), + cyan: colorRamp(chroma(colors.base0C)), + blue: colorRamp(chroma(colors.base0D)), + violet: colorRamp(chroma(colors.base0E)), + magenta: colorRamp(chroma(colors.base0F)), + }, syntax) +} + +export const dark = theme(variant) + +export const meta: Meta = variant.meta diff --git a/styles/src/themes/atelier-heath-light.ts b/styles/src/themes/atelier-heath-light.ts new file mode 100644 index 0000000000000000000000000000000000000000..3afd850fdf2799569b8c4023fc7cdaae1c8591f7 --- /dev/null +++ b/styles/src/themes/atelier-heath-light.ts @@ -0,0 +1,55 @@ +import chroma from "chroma-js" +import { Meta } from "./common/colorScheme" +import { colorRamp, createColorScheme } from "./common/ramps" +import { metaCommon, name, buildSyntax, Variant } from "./common/atelier-common" + +const variant: Variant = { + meta: { + name: `${name} Heath Light`, + ...metaCommon, + url: "https://atelierbram.github.io/syntax-highlighting/atelier-schemes/heath/", + }, + colors: { + base00: "#f7f3f7", + base01: "#d8cad8", + base02: "#ab9bab", + base03: "#9e8f9e", + base04: "#776977", + base05: "#695d69", + base06: "#292329", + base07: "#1b181b", + base08: "#ca402b", + base09: "#a65926", + base0A: "#bb8a35", + base0B: "#918b3b", + base0C: "#159393", + base0D: "#516aec", + base0E: "#7b59c0", + base0F: "#cc33cc", + } +} + +const syntax = buildSyntax(variant) + +const theme = (variant: Variant) => { + const { meta, colors } = variant + + return createColorScheme(meta.name, true, { + neutral: chroma + .scale([ + colors.base00, colors.base01, colors.base02, colors.base03, colors.base04, colors.base05, colors.base06, colors.base07 + ].reverse()), + red: colorRamp(chroma(colors.base08)), + orange: colorRamp(chroma(colors.base09)), + yellow: colorRamp(chroma(colors.base0A)), + green: colorRamp(chroma(colors.base0B)), + cyan: colorRamp(chroma(colors.base0C)), + blue: colorRamp(chroma(colors.base0D)), + violet: colorRamp(chroma(colors.base0E)), + magenta: colorRamp(chroma(colors.base0F)), + }, syntax) +} + +export const dark = theme(variant) + +export const meta: Meta = variant.meta diff --git a/styles/src/themes/atelier-lakeside-light.ts b/styles/src/themes/atelier-lakeside-light.ts new file mode 100644 index 0000000000000000000000000000000000000000..255a4dea9609ae741b1260466caf0d18e88c31e8 --- /dev/null +++ b/styles/src/themes/atelier-lakeside-light.ts @@ -0,0 +1,55 @@ +import chroma from "chroma-js" +import { Meta } from "./common/colorScheme" +import { colorRamp, createColorScheme } from "./common/ramps" +import { metaCommon, name, buildSyntax, Variant } from "./common/atelier-common" + +const variant: Variant = { + meta: { + name: `${name} Lakeside Light`, + ...metaCommon, + url: "https://atelierbram.github.io/syntax-highlighting/atelier-schemes/lakeside/", + }, + colors: { + base00: "#ebf8ff", + base01: "#c1e4f6", + base02: "#7ea2b4", + base03: "#7195a8", + base04: "#5a7b8c", + base05: "#516d7b", + base06: "#1f292e", + base07: "#161b1d", + base08: "#d22d72", + base09: "#935c25", + base0A: "#8a8a0f", + base0B: "#568c3b", + base0C: "#2d8f6f", + base0D: "#257fad", + base0E: "#6b6bb8", + base0F: "#b72dd2", + } +} + +const syntax = buildSyntax(variant) + +const theme = (variant: Variant) => { + const { meta, colors } = variant + + return createColorScheme(meta.name, true, { + neutral: chroma + .scale([ + colors.base00, colors.base01, colors.base02, colors.base03, colors.base04, colors.base05, colors.base06, colors.base07 + ].reverse()), + red: colorRamp(chroma(colors.base08)), + orange: colorRamp(chroma(colors.base09)), + yellow: colorRamp(chroma(colors.base0A)), + green: colorRamp(chroma(colors.base0B)), + cyan: colorRamp(chroma(colors.base0C)), + blue: colorRamp(chroma(colors.base0D)), + violet: colorRamp(chroma(colors.base0E)), + magenta: colorRamp(chroma(colors.base0F)), + }, syntax) +} + +export const dark = theme(variant) + +export const meta: Meta = variant.meta diff --git a/styles/src/themes/atelier-plateau-light.ts b/styles/src/themes/atelier-plateau-light.ts new file mode 100644 index 0000000000000000000000000000000000000000..5f4d2400c101fcba1db31b35054e8e53d9dd5603 --- /dev/null +++ b/styles/src/themes/atelier-plateau-light.ts @@ -0,0 +1,55 @@ +import chroma from "chroma-js" +import { Meta } from "./common/colorScheme" +import { colorRamp, createColorScheme } from "./common/ramps" +import { metaCommon, name, buildSyntax, Variant } from "./common/atelier-common" + +const variant: Variant = { + meta: { + name: `${name} Plateau Light`, + ...metaCommon, + url: "https://atelierbram.github.io/syntax-highlighting/atelier-schemes/plateau/", + }, + colors: { + base00: "#f4ecec", + base01: "#e7dfdf", + base02: "#8a8585", + base03: "#7e7777", + base04: "#655d5d", + base05: "#585050", + base06: "#292424", + base07: "#1b1818", + base08: "#ca4949", + base09: "#b45a3c", + base0A: "#a06e3b", + base0B: "#4b8b8b", + base0C: "#5485b6", + base0D: "#7272ca", + base0E: "#8464c4", + base0F: "#bd5187" + } +} + +const syntax = buildSyntax(variant) + +const theme = (variant: Variant) => { + const { meta, colors } = variant + + return createColorScheme(meta.name, true, { + neutral: chroma + .scale([ + colors.base00, colors.base01, colors.base02, colors.base03, colors.base04, colors.base05, colors.base06, colors.base07 + ].reverse()), + red: colorRamp(chroma(colors.base08)), + orange: colorRamp(chroma(colors.base09)), + yellow: colorRamp(chroma(colors.base0A)), + green: colorRamp(chroma(colors.base0B)), + cyan: colorRamp(chroma(colors.base0C)), + blue: colorRamp(chroma(colors.base0D)), + violet: colorRamp(chroma(colors.base0E)), + magenta: colorRamp(chroma(colors.base0F)), + }, syntax) +} + +export const dark = theme(variant) + +export const meta: Meta = variant.meta diff --git a/styles/src/themes/atelier-savanna-light.ts b/styles/src/themes/atelier-savanna-light.ts new file mode 100644 index 0000000000000000000000000000000000000000..2e1ec9857a0480b46e2bedb4e193f310c1023c65 --- /dev/null +++ b/styles/src/themes/atelier-savanna-light.ts @@ -0,0 +1,55 @@ +import chroma from "chroma-js" +import { Meta } from "./common/colorScheme" +import { colorRamp, createColorScheme } from "./common/ramps" +import { metaCommon, name, buildSyntax, Variant } from "./common/atelier-common" + +const variant: Variant = { + meta: { + name: `${name} Savanna Light`, + ...metaCommon, + url: "https://atelierbram.github.io/syntax-highlighting/atelier-schemes/savanna/", + }, + colors: { + base00: "#ecf4ee", + base01: "#dfe7e2", + base02: "#87928a", + base03: "#78877d", + base04: "#5f6d64", + base05: "#526057", + base06: "#232a25", + base07: "#171c19", + base08: "#b16139", + base09: "#9f713c", + base0A: "#a07e3b", + base0B: "#489963", + base0C: "#1c9aa0", + base0D: "#478c90", + base0E: "#55859b", + base0F: "#867469", + } +} + +const syntax = buildSyntax(variant) + +const theme = (variant: Variant) => { + const { meta, colors } = variant + + return createColorScheme(meta.name, true, { + neutral: chroma + .scale([ + colors.base00, colors.base01, colors.base02, colors.base03, colors.base04, colors.base05, colors.base06, colors.base07 + ].reverse()), + red: colorRamp(chroma(colors.base08)), + orange: colorRamp(chroma(colors.base09)), + yellow: colorRamp(chroma(colors.base0A)), + green: colorRamp(chroma(colors.base0B)), + cyan: colorRamp(chroma(colors.base0C)), + blue: colorRamp(chroma(colors.base0D)), + violet: colorRamp(chroma(colors.base0E)), + magenta: colorRamp(chroma(colors.base0F)), + }, syntax) +} + +export const dark = theme(variant) + +export const meta: Meta = variant.meta diff --git a/styles/src/themes/atelier-seaside-dark.ts b/styles/src/themes/atelier-seaside-dark.ts index 29bdcfb447b9e1b1ac266dedd1df7808ecef64ec..22136a6f13dc005cdf128e5090e8aca19e258291 100644 --- a/styles/src/themes/atelier-seaside-dark.ts +++ b/styles/src/themes/atelier-seaside-dark.ts @@ -7,7 +7,7 @@ const variant: Variant = { meta: { name: `${name} Seaside Dark`, ...metaCommon, - url: "https://atelierbram.github.io/syntax-highlighting/atelier-schemes/savanna/", + url: "https://atelierbram.github.io/syntax-highlighting/atelier-schemes/seaside/", }, colors: { base00: "#131513", diff --git a/styles/src/themes/atelier-seaside-light.ts b/styles/src/themes/atelier-seaside-light.ts new file mode 100644 index 0000000000000000000000000000000000000000..23db80221f5d62fff6a023f1f65c707afd2da13d --- /dev/null +++ b/styles/src/themes/atelier-seaside-light.ts @@ -0,0 +1,55 @@ +import chroma from "chroma-js" +import { Meta } from "./common/colorScheme" +import { colorRamp, createColorScheme } from "./common/ramps" +import { metaCommon, name, buildSyntax, Variant } from "./common/atelier-common" + +const variant: Variant = { + meta: { + name: `${name} Seaside Light`, + ...metaCommon, + url: "https://atelierbram.github.io/syntax-highlighting/atelier-schemes/seaside/", + }, + colors: { + base00: "#f4fbf4", + base01: "#cfe8cf", + base02: "#8ca68c", + base03: "#809980", + base04: "#687d68", + base05: "#5e6e5e", + base06: "#242924", + base07: "#131513", + base08: "#e6193c", + base09: "#87711d", + base0A: "#98981b", + base0B: "#29a329", + base0C: "#1999b3", + base0D: "#3d62f5", + base0E: "#ad2bee", + base0F: "#e619c3", + } +} + +const syntax = buildSyntax(variant) + +const theme = (variant: Variant) => { + const { meta, colors } = variant + + return createColorScheme(meta.name, true, { + neutral: chroma + .scale([ + colors.base00, colors.base01, colors.base02, colors.base03, colors.base04, colors.base05, colors.base06, colors.base07 + ].reverse()), + red: colorRamp(chroma(colors.base08)), + orange: colorRamp(chroma(colors.base09)), + yellow: colorRamp(chroma(colors.base0A)), + green: colorRamp(chroma(colors.base0B)), + cyan: colorRamp(chroma(colors.base0C)), + blue: colorRamp(chroma(colors.base0D)), + violet: colorRamp(chroma(colors.base0E)), + magenta: colorRamp(chroma(colors.base0F)), + }, syntax) +} + +export const dark = theme(variant) + +export const meta: Meta = variant.meta From 51be0efa1f6293d9065aeed63ca25708363e865b Mon Sep 17 00:00:00 2001 From: Nate Butler Date: Thu, 9 Mar 2023 10:47:58 -0500 Subject: [PATCH 58/93] Format --- styles/src/buildLicenses.ts | 2 +- styles/src/styleTree/editor.ts | 2 +- styles/src/themes/andromeda.ts | 2 +- styles/src/themes/atelier-cave-dark.ts | 41 ++++++++++------- styles/src/themes/atelier-cave-light.ts | 45 ++++++++++++------- styles/src/themes/atelier-dune-dark.ts | 41 ++++++++++------- styles/src/themes/atelier-dune-light.ts | 45 ++++++++++++------- styles/src/themes/atelier-estuary-dark.ts | 41 ++++++++++------- styles/src/themes/atelier-estuary-light.ts | 45 ++++++++++++------- styles/src/themes/atelier-forest-dark.ts | 41 ++++++++++------- styles/src/themes/atelier-forest-light.ts | 45 ++++++++++++------- styles/src/themes/atelier-heath-dark.ts | 41 ++++++++++------- styles/src/themes/atelier-heath-light.ts | 43 +++++++++++------- styles/src/themes/atelier-lakeside-dark.ts | 41 ++++++++++------- styles/src/themes/atelier-lakeside-light.ts | 43 +++++++++++------- styles/src/themes/atelier-plateau-dark.ts | 41 ++++++++++------- styles/src/themes/atelier-plateau-light.ts | 45 ++++++++++++------- styles/src/themes/atelier-savanna-dark.ts | 41 ++++++++++------- styles/src/themes/atelier-savanna-light.ts | 43 +++++++++++------- styles/src/themes/atelier-seaside-dark.ts | 41 ++++++++++------- styles/src/themes/atelier-seaside-light.ts | 43 +++++++++++------- styles/src/themes/atelier-sulphurpool-dark.ts | 41 ++++++++++------- .../src/themes/atelier-sulphurpool-light.ts | 45 ++++++++++++------- styles/src/themes/common/atelier-common.ts | 2 +- styles/src/themes/gruvbox-common.ts | 3 +- styles/src/themes/gruvbox-dark-hard.ts | 6 +-- styles/src/themes/gruvbox-dark-soft.ts | 7 ++- styles/src/themes/gruvbox-dark.ts | 7 ++- styles/src/themes/gruvbox-light-hard.ts | 6 +-- styles/src/themes/gruvbox-light-soft.ts | 6 +-- styles/src/themes/gruvbox-light.ts | 6 +-- styles/src/themes/one-dark.ts | 2 +- styles/src/themes/one-light.ts | 2 +- styles/src/themes/rose-pine-dawn.ts | 2 +- styles/src/themes/rose-pine-moon.ts | 2 +- styles/src/themes/rose-pine.ts | 2 +- styles/src/themes/sandcastle.ts | 2 +- styles/src/themes/solarized.ts | 2 +- styles/src/themes/summercamp.ts | 2 +- 39 files changed, 578 insertions(+), 339 deletions(-) diff --git a/styles/src/buildLicenses.ts b/styles/src/buildLicenses.ts index 793a14a3b21d68542d7a17d2643e5c286574ce02..3367e50ff027601db2b68ead242dc3a266b21e1e 100644 --- a/styles/src/buildLicenses.ts +++ b/styles/src/buildLicenses.ts @@ -39,7 +39,7 @@ function getLicenseText( if (typeof meta.license.license_text == "string") { callback(meta, meta.license.license_text) } else { - let license_text_obj: Verification = meta.license.license_text; + let license_text_obj: Verification = meta.license.license_text // The following copied from the example code on nodejs.org: // https://nodejs.org/api/http.html#httpgetoptions-callback https diff --git a/styles/src/styleTree/editor.ts b/styles/src/styleTree/editor.ts index 799363a349191ffe9bd53748d818c7b0cb33177c..64a19d714fa6f5b7edeaa1bac255006f242e8b3f 100644 --- a/styles/src/styleTree/editor.ts +++ b/styles/src/styleTree/editor.ts @@ -90,7 +90,7 @@ export default function editor(colorScheme: ColorScheme) { clicked: { color: colorScheme.ramps.neutral(0.5).alpha(0.7).hex(), }, - } + }, }, foldBackground: foreground(layer, "variant"), }, diff --git a/styles/src/themes/andromeda.ts b/styles/src/themes/andromeda.ts index 369f1d7f2b60ab7b957feaa36fcb70047d606f06..7eba7b1481aeba8b1429b323bb51c0f78c0a6069 100644 --- a/styles/src/themes/andromeda.ts +++ b/styles/src/themes/andromeda.ts @@ -39,7 +39,7 @@ export const meta: Meta = { "https://raw.githubusercontent.com/EliverLara/Andromeda/master/LICENSE.md", license_checksum: "2f7886f1a05cefc2c26f5e49de1a39fa4466413c1ccb06fc80960e73f5ed4b89", - } + }, }, url: "https://github.com/EliverLara/Andromeda", } diff --git a/styles/src/themes/atelier-cave-dark.ts b/styles/src/themes/atelier-cave-dark.ts index 6cb8946b7ac1ddcec8f99c8966eebb5731a79b26..a56e22cd92373997cc40d19eddf5b05e9cad5a02 100644 --- a/styles/src/themes/atelier-cave-dark.ts +++ b/styles/src/themes/atelier-cave-dark.ts @@ -25,8 +25,8 @@ const variant: Variant = { base0C: "#398bc6", base0D: "#576ddb", base0E: "#955ae7", - base0F: "#bf40bf" - } + base0F: "#bf40bf", + }, } const syntax = buildSyntax(variant) @@ -34,20 +34,31 @@ const syntax = buildSyntax(variant) const theme = (variant: Variant) => { const { meta, colors } = variant - return createColorScheme(meta.name, false, { - neutral: chroma - .scale([ - colors.base00, colors.base01, colors.base02, colors.base03, colors.base04, colors.base05, colors.base06, colors.base07 + return createColorScheme( + meta.name, + false, + { + neutral: chroma.scale([ + colors.base00, + colors.base01, + colors.base02, + colors.base03, + colors.base04, + colors.base05, + colors.base06, + colors.base07, ]), - red: colorRamp(chroma(colors.base08)), - orange: colorRamp(chroma(colors.base09)), - yellow: colorRamp(chroma(colors.base0A)), - green: colorRamp(chroma(colors.base0B)), - cyan: colorRamp(chroma(colors.base0C)), - blue: colorRamp(chroma(colors.base0D)), - violet: colorRamp(chroma(colors.base0E)), - magenta: colorRamp(chroma(colors.base0F)), - }, syntax) + red: colorRamp(chroma(colors.base08)), + orange: colorRamp(chroma(colors.base09)), + yellow: colorRamp(chroma(colors.base0A)), + green: colorRamp(chroma(colors.base0B)), + cyan: colorRamp(chroma(colors.base0C)), + blue: colorRamp(chroma(colors.base0D)), + violet: colorRamp(chroma(colors.base0E)), + magenta: colorRamp(chroma(colors.base0F)), + }, + syntax + ) } export const dark = theme(variant) diff --git a/styles/src/themes/atelier-cave-light.ts b/styles/src/themes/atelier-cave-light.ts index b05f730f83283a9bf76dbf169b529caf50a66ffd..3b180752cf97ea1bcc515c904deb20eafc03aea6 100644 --- a/styles/src/themes/atelier-cave-light.ts +++ b/styles/src/themes/atelier-cave-light.ts @@ -25,8 +25,8 @@ const variant: Variant = { base0C: "#398bc6", base0D: "#576ddb", base0E: "#955ae7", - base0F: "#bf40bf" - } + base0F: "#bf40bf", + }, } const syntax = buildSyntax(variant) @@ -34,20 +34,33 @@ const syntax = buildSyntax(variant) const theme = (variant: Variant) => { const { meta, colors } = variant - return createColorScheme(meta.name, true, { - neutral: chroma - .scale([ - colors.base00, colors.base01, colors.base02, colors.base03, colors.base04, colors.base05, colors.base06, colors.base07 - ].reverse()), - red: colorRamp(chroma(colors.base08)), - orange: colorRamp(chroma(colors.base09)), - yellow: colorRamp(chroma(colors.base0A)), - green: colorRamp(chroma(colors.base0B)), - cyan: colorRamp(chroma(colors.base0C)), - blue: colorRamp(chroma(colors.base0D)), - violet: colorRamp(chroma(colors.base0E)), - magenta: colorRamp(chroma(colors.base0F)), - }, syntax) + return createColorScheme( + meta.name, + true, + { + neutral: chroma.scale( + [ + colors.base00, + colors.base01, + colors.base02, + colors.base03, + colors.base04, + colors.base05, + colors.base06, + colors.base07, + ].reverse() + ), + red: colorRamp(chroma(colors.base08)), + orange: colorRamp(chroma(colors.base09)), + yellow: colorRamp(chroma(colors.base0A)), + green: colorRamp(chroma(colors.base0B)), + cyan: colorRamp(chroma(colors.base0C)), + blue: colorRamp(chroma(colors.base0D)), + violet: colorRamp(chroma(colors.base0E)), + magenta: colorRamp(chroma(colors.base0F)), + }, + syntax + ) } export const dark = theme(variant) diff --git a/styles/src/themes/atelier-dune-dark.ts b/styles/src/themes/atelier-dune-dark.ts index b6f90b4c4485130e112a00597524339bc94830d8..0ab402a99d4adf8f1e0ed41979d5cc9973696404 100644 --- a/styles/src/themes/atelier-dune-dark.ts +++ b/styles/src/themes/atelier-dune-dark.ts @@ -25,8 +25,8 @@ const variant: Variant = { base0C: "#1fad83", base0D: "#6684e1", base0E: "#b854d4", - base0F: "#d43552" - } + base0F: "#d43552", + }, } const syntax = buildSyntax(variant) @@ -34,20 +34,31 @@ const syntax = buildSyntax(variant) const theme = (variant: Variant) => { const { meta, colors } = variant - return createColorScheme(meta.name, false, { - neutral: chroma - .scale([ - colors.base00, colors.base01, colors.base02, colors.base03, colors.base04, colors.base05, colors.base06, colors.base07 + return createColorScheme( + meta.name, + false, + { + neutral: chroma.scale([ + colors.base00, + colors.base01, + colors.base02, + colors.base03, + colors.base04, + colors.base05, + colors.base06, + colors.base07, ]), - red: colorRamp(chroma(colors.base08)), - orange: colorRamp(chroma(colors.base09)), - yellow: colorRamp(chroma(colors.base0A)), - green: colorRamp(chroma(colors.base0B)), - cyan: colorRamp(chroma(colors.base0C)), - blue: colorRamp(chroma(colors.base0D)), - violet: colorRamp(chroma(colors.base0E)), - magenta: colorRamp(chroma(colors.base0F)), - }, syntax) + red: colorRamp(chroma(colors.base08)), + orange: colorRamp(chroma(colors.base09)), + yellow: colorRamp(chroma(colors.base0A)), + green: colorRamp(chroma(colors.base0B)), + cyan: colorRamp(chroma(colors.base0C)), + blue: colorRamp(chroma(colors.base0D)), + violet: colorRamp(chroma(colors.base0E)), + magenta: colorRamp(chroma(colors.base0F)), + }, + syntax + ) } export const dark = theme(variant) diff --git a/styles/src/themes/atelier-dune-light.ts b/styles/src/themes/atelier-dune-light.ts index 0a95dc66fc9c9432a5601b9cb2a3c8b0ea9a2a59..e6a09985d5e09f8612d0a41f7b3a898991b9b720 100644 --- a/styles/src/themes/atelier-dune-light.ts +++ b/styles/src/themes/atelier-dune-light.ts @@ -25,8 +25,8 @@ const variant: Variant = { base0C: "#1fad83", base0D: "#6684e1", base0E: "#b854d4", - base0F: "#d43552" - } + base0F: "#d43552", + }, } const syntax = buildSyntax(variant) @@ -34,20 +34,33 @@ const syntax = buildSyntax(variant) const theme = (variant: Variant) => { const { meta, colors } = variant - return createColorScheme(meta.name, true, { - neutral: chroma - .scale([ - colors.base00, colors.base01, colors.base02, colors.base03, colors.base04, colors.base05, colors.base06, colors.base07 - ].reverse()), - red: colorRamp(chroma(colors.base08)), - orange: colorRamp(chroma(colors.base09)), - yellow: colorRamp(chroma(colors.base0A)), - green: colorRamp(chroma(colors.base0B)), - cyan: colorRamp(chroma(colors.base0C)), - blue: colorRamp(chroma(colors.base0D)), - violet: colorRamp(chroma(colors.base0E)), - magenta: colorRamp(chroma(colors.base0F)), - }, syntax) + return createColorScheme( + meta.name, + true, + { + neutral: chroma.scale( + [ + colors.base00, + colors.base01, + colors.base02, + colors.base03, + colors.base04, + colors.base05, + colors.base06, + colors.base07, + ].reverse() + ), + red: colorRamp(chroma(colors.base08)), + orange: colorRamp(chroma(colors.base09)), + yellow: colorRamp(chroma(colors.base0A)), + green: colorRamp(chroma(colors.base0B)), + cyan: colorRamp(chroma(colors.base0C)), + blue: colorRamp(chroma(colors.base0D)), + violet: colorRamp(chroma(colors.base0E)), + magenta: colorRamp(chroma(colors.base0F)), + }, + syntax + ) } export const dark = theme(variant) diff --git a/styles/src/themes/atelier-estuary-dark.ts b/styles/src/themes/atelier-estuary-dark.ts index 94ca7aa63bafda4438f7d672721eaae82a0e1ae2..c4ec50c1e00ed7731d069ed3f559204b9030b10c 100644 --- a/styles/src/themes/atelier-estuary-dark.ts +++ b/styles/src/themes/atelier-estuary-dark.ts @@ -25,8 +25,8 @@ const variant: Variant = { base0C: "#5b9d48", base0D: "#36a166", base0E: "#5f9182", - base0F: "#9d6c7c" - } + base0F: "#9d6c7c", + }, } const syntax = buildSyntax(variant) @@ -34,20 +34,31 @@ const syntax = buildSyntax(variant) const theme = (variant: Variant) => { const { meta, colors } = variant - return createColorScheme(meta.name, false, { - neutral: chroma - .scale([ - colors.base00, colors.base01, colors.base02, colors.base03, colors.base04, colors.base05, colors.base06, colors.base07 + return createColorScheme( + meta.name, + false, + { + neutral: chroma.scale([ + colors.base00, + colors.base01, + colors.base02, + colors.base03, + colors.base04, + colors.base05, + colors.base06, + colors.base07, ]), - red: colorRamp(chroma(colors.base08)), - orange: colorRamp(chroma(colors.base09)), - yellow: colorRamp(chroma(colors.base0A)), - green: colorRamp(chroma(colors.base0B)), - cyan: colorRamp(chroma(colors.base0C)), - blue: colorRamp(chroma(colors.base0D)), - violet: colorRamp(chroma(colors.base0E)), - magenta: colorRamp(chroma(colors.base0F)), - }, syntax) + red: colorRamp(chroma(colors.base08)), + orange: colorRamp(chroma(colors.base09)), + yellow: colorRamp(chroma(colors.base0A)), + green: colorRamp(chroma(colors.base0B)), + cyan: colorRamp(chroma(colors.base0C)), + blue: colorRamp(chroma(colors.base0D)), + violet: colorRamp(chroma(colors.base0E)), + magenta: colorRamp(chroma(colors.base0F)), + }, + syntax + ) } export const dark = theme(variant) diff --git a/styles/src/themes/atelier-estuary-light.ts b/styles/src/themes/atelier-estuary-light.ts index 4dd4b875498aca4e35716fb032a2bfd391a1fbda..6fce0e44833d2d0bf8657a3465bcfb601b262644 100644 --- a/styles/src/themes/atelier-estuary-light.ts +++ b/styles/src/themes/atelier-estuary-light.ts @@ -25,8 +25,8 @@ const variant: Variant = { base0C: "#5b9d48", base0D: "#36a166", base0E: "#5f9182", - base0F: "#9d6c7c" - } + base0F: "#9d6c7c", + }, } const syntax = buildSyntax(variant) @@ -34,20 +34,33 @@ const syntax = buildSyntax(variant) const theme = (variant: Variant) => { const { meta, colors } = variant - return createColorScheme(meta.name, true, { - neutral: chroma - .scale([ - colors.base00, colors.base01, colors.base02, colors.base03, colors.base04, colors.base05, colors.base06, colors.base07 - ].reverse()), - red: colorRamp(chroma(colors.base08)), - orange: colorRamp(chroma(colors.base09)), - yellow: colorRamp(chroma(colors.base0A)), - green: colorRamp(chroma(colors.base0B)), - cyan: colorRamp(chroma(colors.base0C)), - blue: colorRamp(chroma(colors.base0D)), - violet: colorRamp(chroma(colors.base0E)), - magenta: colorRamp(chroma(colors.base0F)), - }, syntax) + return createColorScheme( + meta.name, + true, + { + neutral: chroma.scale( + [ + colors.base00, + colors.base01, + colors.base02, + colors.base03, + colors.base04, + colors.base05, + colors.base06, + colors.base07, + ].reverse() + ), + red: colorRamp(chroma(colors.base08)), + orange: colorRamp(chroma(colors.base09)), + yellow: colorRamp(chroma(colors.base0A)), + green: colorRamp(chroma(colors.base0B)), + cyan: colorRamp(chroma(colors.base0C)), + blue: colorRamp(chroma(colors.base0D)), + violet: colorRamp(chroma(colors.base0E)), + magenta: colorRamp(chroma(colors.base0F)), + }, + syntax + ) } export const dark = theme(variant) diff --git a/styles/src/themes/atelier-forest-dark.ts b/styles/src/themes/atelier-forest-dark.ts index 2bfe285a165497528288a60877fedef252f0023b..7c47c55a830ed780f662d83d9f768d26207dc31e 100644 --- a/styles/src/themes/atelier-forest-dark.ts +++ b/styles/src/themes/atelier-forest-dark.ts @@ -25,8 +25,8 @@ const variant: Variant = { base0C: "#3d97b8", base0D: "#407ee7", base0E: "#6666ea", - base0F: "#c33ff3" - } + base0F: "#c33ff3", + }, } const syntax = buildSyntax(variant) @@ -34,20 +34,31 @@ const syntax = buildSyntax(variant) const theme = (variant: Variant) => { const { meta, colors } = variant - return createColorScheme(meta.name, false, { - neutral: chroma - .scale([ - colors.base00, colors.base01, colors.base02, colors.base03, colors.base04, colors.base05, colors.base06, colors.base07 + return createColorScheme( + meta.name, + false, + { + neutral: chroma.scale([ + colors.base00, + colors.base01, + colors.base02, + colors.base03, + colors.base04, + colors.base05, + colors.base06, + colors.base07, ]), - red: colorRamp(chroma(colors.base08)), - orange: colorRamp(chroma(colors.base09)), - yellow: colorRamp(chroma(colors.base0A)), - green: colorRamp(chroma(colors.base0B)), - cyan: colorRamp(chroma(colors.base0C)), - blue: colorRamp(chroma(colors.base0D)), - violet: colorRamp(chroma(colors.base0E)), - magenta: colorRamp(chroma(colors.base0F)), - }, syntax) + red: colorRamp(chroma(colors.base08)), + orange: colorRamp(chroma(colors.base09)), + yellow: colorRamp(chroma(colors.base0A)), + green: colorRamp(chroma(colors.base0B)), + cyan: colorRamp(chroma(colors.base0C)), + blue: colorRamp(chroma(colors.base0D)), + violet: colorRamp(chroma(colors.base0E)), + magenta: colorRamp(chroma(colors.base0F)), + }, + syntax + ) } export const dark = theme(variant) diff --git a/styles/src/themes/atelier-forest-light.ts b/styles/src/themes/atelier-forest-light.ts index ee9acd7ebb66c082ef39add429e44a41332507f0..8ce06164769a7a8dfa15fc74a77b6aa0f3c9e3af 100644 --- a/styles/src/themes/atelier-forest-light.ts +++ b/styles/src/themes/atelier-forest-light.ts @@ -25,8 +25,8 @@ const variant: Variant = { base0C: "#3d97b8", base0D: "#407ee7", base0E: "#6666ea", - base0F: "#c33ff3" - } + base0F: "#c33ff3", + }, } const syntax = buildSyntax(variant) @@ -34,20 +34,33 @@ const syntax = buildSyntax(variant) const theme = (variant: Variant) => { const { meta, colors } = variant - return createColorScheme(meta.name, true, { - neutral: chroma - .scale([ - colors.base00, colors.base01, colors.base02, colors.base03, colors.base04, colors.base05, colors.base06, colors.base07 - ].reverse()), - red: colorRamp(chroma(colors.base08)), - orange: colorRamp(chroma(colors.base09)), - yellow: colorRamp(chroma(colors.base0A)), - green: colorRamp(chroma(colors.base0B)), - cyan: colorRamp(chroma(colors.base0C)), - blue: colorRamp(chroma(colors.base0D)), - violet: colorRamp(chroma(colors.base0E)), - magenta: colorRamp(chroma(colors.base0F)), - }, syntax) + return createColorScheme( + meta.name, + true, + { + neutral: chroma.scale( + [ + colors.base00, + colors.base01, + colors.base02, + colors.base03, + colors.base04, + colors.base05, + colors.base06, + colors.base07, + ].reverse() + ), + red: colorRamp(chroma(colors.base08)), + orange: colorRamp(chroma(colors.base09)), + yellow: colorRamp(chroma(colors.base0A)), + green: colorRamp(chroma(colors.base0B)), + cyan: colorRamp(chroma(colors.base0C)), + blue: colorRamp(chroma(colors.base0D)), + violet: colorRamp(chroma(colors.base0E)), + magenta: colorRamp(chroma(colors.base0F)), + }, + syntax + ) } export const dark = theme(variant) diff --git a/styles/src/themes/atelier-heath-dark.ts b/styles/src/themes/atelier-heath-dark.ts index 9ae14a8903f1d74bc1befbc0c5476c87308e2ebc..87458ab8f5ab68a30e602de9b62edbe1e4cf5c18 100644 --- a/styles/src/themes/atelier-heath-dark.ts +++ b/styles/src/themes/atelier-heath-dark.ts @@ -25,8 +25,8 @@ const variant: Variant = { base0C: "#159393", base0D: "#516aec", base0E: "#7b59c0", - base0F: "#cc33cc" - } + base0F: "#cc33cc", + }, } const syntax = buildSyntax(variant) @@ -34,20 +34,31 @@ const syntax = buildSyntax(variant) const theme = (variant: Variant) => { const { meta, colors } = variant - return createColorScheme(meta.name, false, { - neutral: chroma - .scale([ - colors.base00, colors.base01, colors.base02, colors.base03, colors.base04, colors.base05, colors.base06, colors.base07 + return createColorScheme( + meta.name, + false, + { + neutral: chroma.scale([ + colors.base00, + colors.base01, + colors.base02, + colors.base03, + colors.base04, + colors.base05, + colors.base06, + colors.base07, ]), - red: colorRamp(chroma(colors.base08)), - orange: colorRamp(chroma(colors.base09)), - yellow: colorRamp(chroma(colors.base0A)), - green: colorRamp(chroma(colors.base0B)), - cyan: colorRamp(chroma(colors.base0C)), - blue: colorRamp(chroma(colors.base0D)), - violet: colorRamp(chroma(colors.base0E)), - magenta: colorRamp(chroma(colors.base0F)), - }, syntax) + red: colorRamp(chroma(colors.base08)), + orange: colorRamp(chroma(colors.base09)), + yellow: colorRamp(chroma(colors.base0A)), + green: colorRamp(chroma(colors.base0B)), + cyan: colorRamp(chroma(colors.base0C)), + blue: colorRamp(chroma(colors.base0D)), + violet: colorRamp(chroma(colors.base0E)), + magenta: colorRamp(chroma(colors.base0F)), + }, + syntax + ) } export const dark = theme(variant) diff --git a/styles/src/themes/atelier-heath-light.ts b/styles/src/themes/atelier-heath-light.ts index 3afd850fdf2799569b8c4023fc7cdaae1c8591f7..3db34370418f1cd27e305a3175e045e591e36ae9 100644 --- a/styles/src/themes/atelier-heath-light.ts +++ b/styles/src/themes/atelier-heath-light.ts @@ -26,7 +26,7 @@ const variant: Variant = { base0D: "#516aec", base0E: "#7b59c0", base0F: "#cc33cc", - } + }, } const syntax = buildSyntax(variant) @@ -34,20 +34,33 @@ const syntax = buildSyntax(variant) const theme = (variant: Variant) => { const { meta, colors } = variant - return createColorScheme(meta.name, true, { - neutral: chroma - .scale([ - colors.base00, colors.base01, colors.base02, colors.base03, colors.base04, colors.base05, colors.base06, colors.base07 - ].reverse()), - red: colorRamp(chroma(colors.base08)), - orange: colorRamp(chroma(colors.base09)), - yellow: colorRamp(chroma(colors.base0A)), - green: colorRamp(chroma(colors.base0B)), - cyan: colorRamp(chroma(colors.base0C)), - blue: colorRamp(chroma(colors.base0D)), - violet: colorRamp(chroma(colors.base0E)), - magenta: colorRamp(chroma(colors.base0F)), - }, syntax) + return createColorScheme( + meta.name, + true, + { + neutral: chroma.scale( + [ + colors.base00, + colors.base01, + colors.base02, + colors.base03, + colors.base04, + colors.base05, + colors.base06, + colors.base07, + ].reverse() + ), + red: colorRamp(chroma(colors.base08)), + orange: colorRamp(chroma(colors.base09)), + yellow: colorRamp(chroma(colors.base0A)), + green: colorRamp(chroma(colors.base0B)), + cyan: colorRamp(chroma(colors.base0C)), + blue: colorRamp(chroma(colors.base0D)), + violet: colorRamp(chroma(colors.base0E)), + magenta: colorRamp(chroma(colors.base0F)), + }, + syntax + ) } export const dark = theme(variant) diff --git a/styles/src/themes/atelier-lakeside-dark.ts b/styles/src/themes/atelier-lakeside-dark.ts index 45f5733cf9326c42ee2884f15086a9ba639bb6d2..a8297ef9fd307243f1c9c84f3caa1e627120a19e 100644 --- a/styles/src/themes/atelier-lakeside-dark.ts +++ b/styles/src/themes/atelier-lakeside-dark.ts @@ -25,8 +25,8 @@ const variant: Variant = { base0C: "#2d8f6f", base0D: "#257fad", base0E: "#6b6bb8", - base0F: "#b72dd2" - } + base0F: "#b72dd2", + }, } const syntax = buildSyntax(variant) @@ -34,20 +34,31 @@ const syntax = buildSyntax(variant) const theme = (variant: Variant) => { const { meta, colors } = variant - return createColorScheme(meta.name, false, { - neutral: chroma - .scale([ - colors.base00, colors.base01, colors.base02, colors.base03, colors.base04, colors.base05, colors.base06, colors.base07 + return createColorScheme( + meta.name, + false, + { + neutral: chroma.scale([ + colors.base00, + colors.base01, + colors.base02, + colors.base03, + colors.base04, + colors.base05, + colors.base06, + colors.base07, ]), - red: colorRamp(chroma(colors.base08)), - orange: colorRamp(chroma(colors.base09)), - yellow: colorRamp(chroma(colors.base0A)), - green: colorRamp(chroma(colors.base0B)), - cyan: colorRamp(chroma(colors.base0C)), - blue: colorRamp(chroma(colors.base0D)), - violet: colorRamp(chroma(colors.base0E)), - magenta: colorRamp(chroma(colors.base0F)), - }, syntax) + red: colorRamp(chroma(colors.base08)), + orange: colorRamp(chroma(colors.base09)), + yellow: colorRamp(chroma(colors.base0A)), + green: colorRamp(chroma(colors.base0B)), + cyan: colorRamp(chroma(colors.base0C)), + blue: colorRamp(chroma(colors.base0D)), + violet: colorRamp(chroma(colors.base0E)), + magenta: colorRamp(chroma(colors.base0F)), + }, + syntax + ) } export const dark = theme(variant) diff --git a/styles/src/themes/atelier-lakeside-light.ts b/styles/src/themes/atelier-lakeside-light.ts index 255a4dea9609ae741b1260466caf0d18e88c31e8..408fabcaf36a50df5229ea0034d12c67bd3b3562 100644 --- a/styles/src/themes/atelier-lakeside-light.ts +++ b/styles/src/themes/atelier-lakeside-light.ts @@ -26,7 +26,7 @@ const variant: Variant = { base0D: "#257fad", base0E: "#6b6bb8", base0F: "#b72dd2", - } + }, } const syntax = buildSyntax(variant) @@ -34,20 +34,33 @@ const syntax = buildSyntax(variant) const theme = (variant: Variant) => { const { meta, colors } = variant - return createColorScheme(meta.name, true, { - neutral: chroma - .scale([ - colors.base00, colors.base01, colors.base02, colors.base03, colors.base04, colors.base05, colors.base06, colors.base07 - ].reverse()), - red: colorRamp(chroma(colors.base08)), - orange: colorRamp(chroma(colors.base09)), - yellow: colorRamp(chroma(colors.base0A)), - green: colorRamp(chroma(colors.base0B)), - cyan: colorRamp(chroma(colors.base0C)), - blue: colorRamp(chroma(colors.base0D)), - violet: colorRamp(chroma(colors.base0E)), - magenta: colorRamp(chroma(colors.base0F)), - }, syntax) + return createColorScheme( + meta.name, + true, + { + neutral: chroma.scale( + [ + colors.base00, + colors.base01, + colors.base02, + colors.base03, + colors.base04, + colors.base05, + colors.base06, + colors.base07, + ].reverse() + ), + red: colorRamp(chroma(colors.base08)), + orange: colorRamp(chroma(colors.base09)), + yellow: colorRamp(chroma(colors.base0A)), + green: colorRamp(chroma(colors.base0B)), + cyan: colorRamp(chroma(colors.base0C)), + blue: colorRamp(chroma(colors.base0D)), + violet: colorRamp(chroma(colors.base0E)), + magenta: colorRamp(chroma(colors.base0F)), + }, + syntax + ) } export const dark = theme(variant) diff --git a/styles/src/themes/atelier-plateau-dark.ts b/styles/src/themes/atelier-plateau-dark.ts index 22510730e7f5a40a2d42ceb3b53bb37e852fe7c5..731cb824e44eba0590c5f1dc4804121aa7f97cd9 100644 --- a/styles/src/themes/atelier-plateau-dark.ts +++ b/styles/src/themes/atelier-plateau-dark.ts @@ -25,8 +25,8 @@ const variant: Variant = { base0C: "#5485b6", base0D: "#7272ca", base0E: "#8464c4", - base0F: "#bd5187" - } + base0F: "#bd5187", + }, } const syntax = buildSyntax(variant) @@ -34,20 +34,31 @@ const syntax = buildSyntax(variant) const theme = (variant: Variant) => { const { meta, colors } = variant - return createColorScheme(meta.name, false, { - neutral: chroma - .scale([ - colors.base00, colors.base01, colors.base02, colors.base03, colors.base04, colors.base05, colors.base06, colors.base07 + return createColorScheme( + meta.name, + false, + { + neutral: chroma.scale([ + colors.base00, + colors.base01, + colors.base02, + colors.base03, + colors.base04, + colors.base05, + colors.base06, + colors.base07, ]), - red: colorRamp(chroma(colors.base08)), - orange: colorRamp(chroma(colors.base09)), - yellow: colorRamp(chroma(colors.base0A)), - green: colorRamp(chroma(colors.base0B)), - cyan: colorRamp(chroma(colors.base0C)), - blue: colorRamp(chroma(colors.base0D)), - violet: colorRamp(chroma(colors.base0E)), - magenta: colorRamp(chroma(colors.base0F)), - }, syntax) + red: colorRamp(chroma(colors.base08)), + orange: colorRamp(chroma(colors.base09)), + yellow: colorRamp(chroma(colors.base0A)), + green: colorRamp(chroma(colors.base0B)), + cyan: colorRamp(chroma(colors.base0C)), + blue: colorRamp(chroma(colors.base0D)), + violet: colorRamp(chroma(colors.base0E)), + magenta: colorRamp(chroma(colors.base0F)), + }, + syntax + ) } export const dark = theme(variant) diff --git a/styles/src/themes/atelier-plateau-light.ts b/styles/src/themes/atelier-plateau-light.ts index 5f4d2400c101fcba1db31b35054e8e53d9dd5603..96f295a69518b1216482776e44d5b36912f526da 100644 --- a/styles/src/themes/atelier-plateau-light.ts +++ b/styles/src/themes/atelier-plateau-light.ts @@ -25,8 +25,8 @@ const variant: Variant = { base0C: "#5485b6", base0D: "#7272ca", base0E: "#8464c4", - base0F: "#bd5187" - } + base0F: "#bd5187", + }, } const syntax = buildSyntax(variant) @@ -34,20 +34,33 @@ const syntax = buildSyntax(variant) const theme = (variant: Variant) => { const { meta, colors } = variant - return createColorScheme(meta.name, true, { - neutral: chroma - .scale([ - colors.base00, colors.base01, colors.base02, colors.base03, colors.base04, colors.base05, colors.base06, colors.base07 - ].reverse()), - red: colorRamp(chroma(colors.base08)), - orange: colorRamp(chroma(colors.base09)), - yellow: colorRamp(chroma(colors.base0A)), - green: colorRamp(chroma(colors.base0B)), - cyan: colorRamp(chroma(colors.base0C)), - blue: colorRamp(chroma(colors.base0D)), - violet: colorRamp(chroma(colors.base0E)), - magenta: colorRamp(chroma(colors.base0F)), - }, syntax) + return createColorScheme( + meta.name, + true, + { + neutral: chroma.scale( + [ + colors.base00, + colors.base01, + colors.base02, + colors.base03, + colors.base04, + colors.base05, + colors.base06, + colors.base07, + ].reverse() + ), + red: colorRamp(chroma(colors.base08)), + orange: colorRamp(chroma(colors.base09)), + yellow: colorRamp(chroma(colors.base0A)), + green: colorRamp(chroma(colors.base0B)), + cyan: colorRamp(chroma(colors.base0C)), + blue: colorRamp(chroma(colors.base0D)), + violet: colorRamp(chroma(colors.base0E)), + magenta: colorRamp(chroma(colors.base0F)), + }, + syntax + ) } export const dark = theme(variant) diff --git a/styles/src/themes/atelier-savanna-dark.ts b/styles/src/themes/atelier-savanna-dark.ts index c2fa1efa6d958f2f61b3fe1e124fc25e22425e26..dfcb4f27cbedd41608b941da97172d083e7a8e76 100644 --- a/styles/src/themes/atelier-savanna-dark.ts +++ b/styles/src/themes/atelier-savanna-dark.ts @@ -25,8 +25,8 @@ const variant: Variant = { base0C: "#1c9aa0", base0D: "#478c90", base0E: "#55859b", - base0F: "#867469" - } + base0F: "#867469", + }, } const syntax = buildSyntax(variant) @@ -34,20 +34,31 @@ const syntax = buildSyntax(variant) const theme = (variant: Variant) => { const { meta, colors } = variant - return createColorScheme(meta.name, false, { - neutral: chroma - .scale([ - colors.base00, colors.base01, colors.base02, colors.base03, colors.base04, colors.base05, colors.base06, colors.base07 + return createColorScheme( + meta.name, + false, + { + neutral: chroma.scale([ + colors.base00, + colors.base01, + colors.base02, + colors.base03, + colors.base04, + colors.base05, + colors.base06, + colors.base07, ]), - red: colorRamp(chroma(colors.base08)), - orange: colorRamp(chroma(colors.base09)), - yellow: colorRamp(chroma(colors.base0A)), - green: colorRamp(chroma(colors.base0B)), - cyan: colorRamp(chroma(colors.base0C)), - blue: colorRamp(chroma(colors.base0D)), - violet: colorRamp(chroma(colors.base0E)), - magenta: colorRamp(chroma(colors.base0F)), - }, syntax) + red: colorRamp(chroma(colors.base08)), + orange: colorRamp(chroma(colors.base09)), + yellow: colorRamp(chroma(colors.base0A)), + green: colorRamp(chroma(colors.base0B)), + cyan: colorRamp(chroma(colors.base0C)), + blue: colorRamp(chroma(colors.base0D)), + violet: colorRamp(chroma(colors.base0E)), + magenta: colorRamp(chroma(colors.base0F)), + }, + syntax + ) } export const dark = theme(variant) diff --git a/styles/src/themes/atelier-savanna-light.ts b/styles/src/themes/atelier-savanna-light.ts index 2e1ec9857a0480b46e2bedb4e193f310c1023c65..4bc1389fc9cf3cb3b4870a58665a510a65d4c9e2 100644 --- a/styles/src/themes/atelier-savanna-light.ts +++ b/styles/src/themes/atelier-savanna-light.ts @@ -26,7 +26,7 @@ const variant: Variant = { base0D: "#478c90", base0E: "#55859b", base0F: "#867469", - } + }, } const syntax = buildSyntax(variant) @@ -34,20 +34,33 @@ const syntax = buildSyntax(variant) const theme = (variant: Variant) => { const { meta, colors } = variant - return createColorScheme(meta.name, true, { - neutral: chroma - .scale([ - colors.base00, colors.base01, colors.base02, colors.base03, colors.base04, colors.base05, colors.base06, colors.base07 - ].reverse()), - red: colorRamp(chroma(colors.base08)), - orange: colorRamp(chroma(colors.base09)), - yellow: colorRamp(chroma(colors.base0A)), - green: colorRamp(chroma(colors.base0B)), - cyan: colorRamp(chroma(colors.base0C)), - blue: colorRamp(chroma(colors.base0D)), - violet: colorRamp(chroma(colors.base0E)), - magenta: colorRamp(chroma(colors.base0F)), - }, syntax) + return createColorScheme( + meta.name, + true, + { + neutral: chroma.scale( + [ + colors.base00, + colors.base01, + colors.base02, + colors.base03, + colors.base04, + colors.base05, + colors.base06, + colors.base07, + ].reverse() + ), + red: colorRamp(chroma(colors.base08)), + orange: colorRamp(chroma(colors.base09)), + yellow: colorRamp(chroma(colors.base0A)), + green: colorRamp(chroma(colors.base0B)), + cyan: colorRamp(chroma(colors.base0C)), + blue: colorRamp(chroma(colors.base0D)), + violet: colorRamp(chroma(colors.base0E)), + magenta: colorRamp(chroma(colors.base0F)), + }, + syntax + ) } export const dark = theme(variant) diff --git a/styles/src/themes/atelier-seaside-dark.ts b/styles/src/themes/atelier-seaside-dark.ts index 22136a6f13dc005cdf128e5090e8aca19e258291..1326a277861e417711c3ea30d39230b227c9ac51 100644 --- a/styles/src/themes/atelier-seaside-dark.ts +++ b/styles/src/themes/atelier-seaside-dark.ts @@ -25,8 +25,8 @@ const variant: Variant = { base0C: "#1999b3", base0D: "#3d62f5", base0E: "#ad2bee", - base0F: "#e619c3" - } + base0F: "#e619c3", + }, } const syntax = buildSyntax(variant) @@ -34,20 +34,31 @@ const syntax = buildSyntax(variant) const theme = (variant: Variant) => { const { meta, colors } = variant - return createColorScheme(meta.name, false, { - neutral: chroma - .scale([ - colors.base00, colors.base01, colors.base02, colors.base03, colors.base04, colors.base05, colors.base06, colors.base07 + return createColorScheme( + meta.name, + false, + { + neutral: chroma.scale([ + colors.base00, + colors.base01, + colors.base02, + colors.base03, + colors.base04, + colors.base05, + colors.base06, + colors.base07, ]), - red: colorRamp(chroma(colors.base08)), - orange: colorRamp(chroma(colors.base09)), - yellow: colorRamp(chroma(colors.base0A)), - green: colorRamp(chroma(colors.base0B)), - cyan: colorRamp(chroma(colors.base0C)), - blue: colorRamp(chroma(colors.base0D)), - violet: colorRamp(chroma(colors.base0E)), - magenta: colorRamp(chroma(colors.base0F)), - }, syntax) + red: colorRamp(chroma(colors.base08)), + orange: colorRamp(chroma(colors.base09)), + yellow: colorRamp(chroma(colors.base0A)), + green: colorRamp(chroma(colors.base0B)), + cyan: colorRamp(chroma(colors.base0C)), + blue: colorRamp(chroma(colors.base0D)), + violet: colorRamp(chroma(colors.base0E)), + magenta: colorRamp(chroma(colors.base0F)), + }, + syntax + ) } export const dark = theme(variant) diff --git a/styles/src/themes/atelier-seaside-light.ts b/styles/src/themes/atelier-seaside-light.ts index 23db80221f5d62fff6a023f1f65c707afd2da13d..6f6823718aed9ba4e3d7325b9968b11ba5472b40 100644 --- a/styles/src/themes/atelier-seaside-light.ts +++ b/styles/src/themes/atelier-seaside-light.ts @@ -26,7 +26,7 @@ const variant: Variant = { base0D: "#3d62f5", base0E: "#ad2bee", base0F: "#e619c3", - } + }, } const syntax = buildSyntax(variant) @@ -34,20 +34,33 @@ const syntax = buildSyntax(variant) const theme = (variant: Variant) => { const { meta, colors } = variant - return createColorScheme(meta.name, true, { - neutral: chroma - .scale([ - colors.base00, colors.base01, colors.base02, colors.base03, colors.base04, colors.base05, colors.base06, colors.base07 - ].reverse()), - red: colorRamp(chroma(colors.base08)), - orange: colorRamp(chroma(colors.base09)), - yellow: colorRamp(chroma(colors.base0A)), - green: colorRamp(chroma(colors.base0B)), - cyan: colorRamp(chroma(colors.base0C)), - blue: colorRamp(chroma(colors.base0D)), - violet: colorRamp(chroma(colors.base0E)), - magenta: colorRamp(chroma(colors.base0F)), - }, syntax) + return createColorScheme( + meta.name, + true, + { + neutral: chroma.scale( + [ + colors.base00, + colors.base01, + colors.base02, + colors.base03, + colors.base04, + colors.base05, + colors.base06, + colors.base07, + ].reverse() + ), + red: colorRamp(chroma(colors.base08)), + orange: colorRamp(chroma(colors.base09)), + yellow: colorRamp(chroma(colors.base0A)), + green: colorRamp(chroma(colors.base0B)), + cyan: colorRamp(chroma(colors.base0C)), + blue: colorRamp(chroma(colors.base0D)), + violet: colorRamp(chroma(colors.base0E)), + magenta: colorRamp(chroma(colors.base0F)), + }, + syntax + ) } export const dark = theme(variant) diff --git a/styles/src/themes/atelier-sulphurpool-dark.ts b/styles/src/themes/atelier-sulphurpool-dark.ts index 2d282deaa2b591b88a0e48f3c46eefe30528f31f..dcfc0d932a67d7081f5bcdb195f6fc57cfc2d79f 100644 --- a/styles/src/themes/atelier-sulphurpool-dark.ts +++ b/styles/src/themes/atelier-sulphurpool-dark.ts @@ -25,8 +25,8 @@ const variant: Variant = { base0C: "#22a2c9", base0D: "#3d8fd1", base0E: "#6679cc", - base0F: "#9c637a" - } + base0F: "#9c637a", + }, } const syntax = buildSyntax(variant) @@ -34,20 +34,31 @@ const syntax = buildSyntax(variant) const theme = (variant: Variant) => { const { meta, colors } = variant - return createColorScheme(meta.name, false, { - neutral: chroma - .scale([ - colors.base00, colors.base01, colors.base02, colors.base03, colors.base04, colors.base05, colors.base06, colors.base07 + return createColorScheme( + meta.name, + false, + { + neutral: chroma.scale([ + colors.base00, + colors.base01, + colors.base02, + colors.base03, + colors.base04, + colors.base05, + colors.base06, + colors.base07, ]), - red: colorRamp(chroma(colors.base08)), - orange: colorRamp(chroma(colors.base09)), - yellow: colorRamp(chroma(colors.base0A)), - green: colorRamp(chroma(colors.base0B)), - cyan: colorRamp(chroma(colors.base0C)), - blue: colorRamp(chroma(colors.base0D)), - violet: colorRamp(chroma(colors.base0E)), - magenta: colorRamp(chroma(colors.base0F)), - }, syntax) + red: colorRamp(chroma(colors.base08)), + orange: colorRamp(chroma(colors.base09)), + yellow: colorRamp(chroma(colors.base0A)), + green: colorRamp(chroma(colors.base0B)), + cyan: colorRamp(chroma(colors.base0C)), + blue: colorRamp(chroma(colors.base0D)), + violet: colorRamp(chroma(colors.base0E)), + magenta: colorRamp(chroma(colors.base0F)), + }, + syntax + ) } export const dark = theme(variant) diff --git a/styles/src/themes/atelier-sulphurpool-light.ts b/styles/src/themes/atelier-sulphurpool-light.ts index 943ceedf2b3d582e2005fdc5e1c35d9536dab12e..b2b5f7c328ba86be296be0fb938bf850571dbef9 100644 --- a/styles/src/themes/atelier-sulphurpool-light.ts +++ b/styles/src/themes/atelier-sulphurpool-light.ts @@ -25,8 +25,8 @@ const variant: Variant = { base0C: "#22a2c9", base0D: "#3d8fd1", base0E: "#6679cc", - base0F: "#9c637a" - } + base0F: "#9c637a", + }, } const syntax = buildSyntax(variant) @@ -34,20 +34,33 @@ const syntax = buildSyntax(variant) const theme = (variant: Variant) => { const { meta, colors } = variant - return createColorScheme(meta.name, true, { - neutral: chroma - .scale([ - colors.base00, colors.base01, colors.base02, colors.base03, colors.base04, colors.base05, colors.base06, colors.base07 - ].reverse()), - red: colorRamp(chroma(colors.base08)), - orange: colorRamp(chroma(colors.base09)), - yellow: colorRamp(chroma(colors.base0A)), - green: colorRamp(chroma(colors.base0B)), - cyan: colorRamp(chroma(colors.base0C)), - blue: colorRamp(chroma(colors.base0D)), - violet: colorRamp(chroma(colors.base0E)), - magenta: colorRamp(chroma(colors.base0F)), - }, syntax) + return createColorScheme( + meta.name, + true, + { + neutral: chroma.scale( + [ + colors.base00, + colors.base01, + colors.base02, + colors.base03, + colors.base04, + colors.base05, + colors.base06, + colors.base07, + ].reverse() + ), + red: colorRamp(chroma(colors.base08)), + orange: colorRamp(chroma(colors.base09)), + yellow: colorRamp(chroma(colors.base0A)), + green: colorRamp(chroma(colors.base0B)), + cyan: colorRamp(chroma(colors.base0C)), + blue: colorRamp(chroma(colors.base0D)), + violet: colorRamp(chroma(colors.base0E)), + magenta: colorRamp(chroma(colors.base0F)), + }, + syntax + ) } export const dark = theme(variant) diff --git a/styles/src/themes/common/atelier-common.ts b/styles/src/themes/common/atelier-common.ts index 25dda87c6118c5c8776ec198fb4d1f404c96858c..08a915d01948f300441d0904cbff2fd406e3dcba 100644 --- a/styles/src/themes/common/atelier-common.ts +++ b/styles/src/themes/common/atelier-common.ts @@ -33,7 +33,7 @@ export const metaCommon: { https_url: "https://atelierbram.mit-license.org/license.txt", license_checksum: "f95ce526ef4e7eecf7a832bba0e3451cc1000f9ce63eb01ed6f64f8109f5d0a5", - } + }, }, } diff --git a/styles/src/themes/gruvbox-common.ts b/styles/src/themes/gruvbox-common.ts index c3e63a31cf12ca19419548677a598661cafae39c..c42362c11c007e5371ad7134c7300667fe04304e 100644 --- a/styles/src/themes/gruvbox-common.ts +++ b/styles/src/themes/gruvbox-common.ts @@ -248,7 +248,8 @@ export const meta: Meta = { name, license: { SPDX: "MIT", // "MIT/X11" - license_text: "Copyright \n\nPermission 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:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE 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." + license_text: + "Copyright \n\nPermission 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:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE 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.", }, author: "morhetz ", url: "https://github.com/morhetz/gruvbox", diff --git a/styles/src/themes/gruvbox-dark-hard.ts b/styles/src/themes/gruvbox-dark-hard.ts index a6e20e1020945474320537b332884d123fbaa543..3723de49015ab0cfe0f975a15943c4d4e7f35548 100644 --- a/styles/src/themes/gruvbox-dark-hard.ts +++ b/styles/src/themes/gruvbox-dark-hard.ts @@ -1,6 +1,6 @@ -import { darkHard as dark, meta as commonMeta } from "./gruvbox-common"; +import { darkHard as dark, meta as commonMeta } from "./gruvbox-common" -let meta = { ...commonMeta }; +let meta = { ...commonMeta } meta.name = `${commonMeta.name} Dark Hard` -export { dark, meta } \ No newline at end of file +export { dark, meta } diff --git a/styles/src/themes/gruvbox-dark-soft.ts b/styles/src/themes/gruvbox-dark-soft.ts index 7eaefaa99ac3df5190506820215a581036ae1eb7..2887572eadb6e757e0611b00301c3edb790fda59 100644 --- a/styles/src/themes/gruvbox-dark-soft.ts +++ b/styles/src/themes/gruvbox-dark-soft.ts @@ -1,7 +1,6 @@ -import { darkSoft as dark, meta as commonMeta } from "./gruvbox-common"; +import { darkSoft as dark, meta as commonMeta } from "./gruvbox-common" - -let meta = { ...commonMeta }; +let meta = { ...commonMeta } meta.name = `${commonMeta.name} Dark Soft` -export { dark, meta } \ No newline at end of file +export { dark, meta } diff --git a/styles/src/themes/gruvbox-dark.ts b/styles/src/themes/gruvbox-dark.ts index ea21933714e2bcc33e0eed28bb46f2998ebb0a16..cff7bd8bf94af1a839c043bb93165d7077912c6f 100644 --- a/styles/src/themes/gruvbox-dark.ts +++ b/styles/src/themes/gruvbox-dark.ts @@ -1,7 +1,6 @@ -import { darkDefault as dark, meta as commonMeta } from "./gruvbox-common"; +import { darkDefault as dark, meta as commonMeta } from "./gruvbox-common" - -let meta = { ...commonMeta }; +let meta = { ...commonMeta } meta.name = `${commonMeta.name} Dark` -export { dark, meta } \ No newline at end of file +export { dark, meta } diff --git a/styles/src/themes/gruvbox-light-hard.ts b/styles/src/themes/gruvbox-light-hard.ts index b0f42ca4b7aea8fea65e1565cf61388045c8371f..cf998ce588bfc56b168e05a3c03cd2c9a568dadd 100644 --- a/styles/src/themes/gruvbox-light-hard.ts +++ b/styles/src/themes/gruvbox-light-hard.ts @@ -1,6 +1,6 @@ -import { lightHard as light, meta as commonMeta } from "./gruvbox-common"; +import { lightHard as light, meta as commonMeta } from "./gruvbox-common" -let meta = { ...commonMeta }; +let meta = { ...commonMeta } meta.name = `${commonMeta.name} Dark Soft` -export { light, meta } \ No newline at end of file +export { light, meta } diff --git a/styles/src/themes/gruvbox-light-soft.ts b/styles/src/themes/gruvbox-light-soft.ts index 6743d29232931de6b5041977ba0c87cbec7a1e1a..90ec82e965e6ef5f36c173fee837162e0b1aefaf 100644 --- a/styles/src/themes/gruvbox-light-soft.ts +++ b/styles/src/themes/gruvbox-light-soft.ts @@ -1,6 +1,6 @@ -import { lightSoft as light, meta as commonMeta } from "./gruvbox-common"; +import { lightSoft as light, meta as commonMeta } from "./gruvbox-common" -let meta = { ...commonMeta }; +let meta = { ...commonMeta } meta.name = `${commonMeta.name} Light Soft` -export { light, meta } \ No newline at end of file +export { light, meta } diff --git a/styles/src/themes/gruvbox-light.ts b/styles/src/themes/gruvbox-light.ts index f64778d8564dbdcfd4e56b64d338ae1d7f3e3b2a..e8f355cd11482c3ca82462c5ca1fa239071e6b84 100644 --- a/styles/src/themes/gruvbox-light.ts +++ b/styles/src/themes/gruvbox-light.ts @@ -1,6 +1,6 @@ -import { lightDefault as light, meta as commonMeta } from "./gruvbox-common"; +import { lightDefault as light, meta as commonMeta } from "./gruvbox-common" -let meta = { ...commonMeta }; +let meta = { ...commonMeta } meta.name = `${commonMeta.name} Light` -export { light, meta } \ No newline at end of file +export { light, meta } diff --git a/styles/src/themes/one-dark.ts b/styles/src/themes/one-dark.ts index f99b4114f3ec9fa35f97705cb708f3c300e460fe..85417a0e68651341edded4689425b15a0d8f29b1 100644 --- a/styles/src/themes/one-dark.ts +++ b/styles/src/themes/one-dark.ts @@ -79,7 +79,7 @@ export const meta: Meta = { "https://raw.githubusercontent.com/atom/atom/master/packages/one-light-ui/LICENSE.md", license_checksum: "d5af8fc171f6f600c0ab4e7597dca398dda80dbe6821ce01cef78e859e7a00f8", - } + }, }, url: "https://github.com/atom/atom/tree/master/packages/one-dark-ui", } diff --git a/styles/src/themes/one-light.ts b/styles/src/themes/one-light.ts index 534e4c16481a6dac6635f74084a2fcea1b36bb8d..7bf21aee17d4871681b33174e3b20bea06ced9fe 100644 --- a/styles/src/themes/one-light.ts +++ b/styles/src/themes/one-light.ts @@ -78,7 +78,7 @@ export const meta: Meta = { "https://raw.githubusercontent.com/atom/atom/master/packages/one-light-ui/LICENSE.md", license_checksum: "d5af8fc171f6f600c0ab4e7597dca398dda80dbe6821ce01cef78e859e7a00f8", - } + }, }, url: "https://github.com/atom/atom/tree/master/packages/one-light-ui", } diff --git a/styles/src/themes/rose-pine-dawn.ts b/styles/src/themes/rose-pine-dawn.ts index 7f7d52079d4b2ea0977c04e8b2e121b6e7f14bf3..427b05f72b8e5672897b7457738d4c43e2c6f603 100644 --- a/styles/src/themes/rose-pine-dawn.ts +++ b/styles/src/themes/rose-pine-dawn.ts @@ -39,7 +39,7 @@ export const meta: Meta = { "https://raw.githubusercontent.com/edunfelt/base16-rose-pine-scheme/main/LICENSE", license_checksum: "6ca1b9da8c78c8441c5aa43d024a4e4a7bf59d1ecca1480196e94fda0f91ee4a", - } + }, }, url: "https://github.com/edunfelt/base16-rose-pine-scheme", } diff --git a/styles/src/themes/rose-pine-moon.ts b/styles/src/themes/rose-pine-moon.ts index a89d44487e04a9e48836b619d78967ea1576953f..be2f5a8dafd366803f13737c75bdb48d7e101aa9 100644 --- a/styles/src/themes/rose-pine-moon.ts +++ b/styles/src/themes/rose-pine-moon.ts @@ -39,7 +39,7 @@ export const meta: Meta = { "https://raw.githubusercontent.com/edunfelt/base16-rose-pine-scheme/main/LICENSE", license_checksum: "6ca1b9da8c78c8441c5aa43d024a4e4a7bf59d1ecca1480196e94fda0f91ee4a", - } + }, }, url: "https://github.com/edunfelt/base16-rose-pine-scheme", } diff --git a/styles/src/themes/rose-pine.ts b/styles/src/themes/rose-pine.ts index 87c9d34ffefe5d2e12bb1ce8cdfbfd3e6f058b6a..944550f1250ad01146f8622a8199cf027f4658ab 100644 --- a/styles/src/themes/rose-pine.ts +++ b/styles/src/themes/rose-pine.ts @@ -37,7 +37,7 @@ export const meta: Meta = { "https://raw.githubusercontent.com/edunfelt/base16-rose-pine-scheme/main/LICENSE", license_checksum: "6ca1b9da8c78c8441c5aa43d024a4e4a7bf59d1ecca1480196e94fda0f91ee4a", - } + }, }, url: "https://github.com/edunfelt/base16-rose-pine-scheme", } diff --git a/styles/src/themes/sandcastle.ts b/styles/src/themes/sandcastle.ts index 86179db3dbacd91f42a38739acb42efb55e7c745..483f01b27a1850463348e0a9c575086a014d5f1b 100644 --- a/styles/src/themes/sandcastle.ts +++ b/styles/src/themes/sandcastle.ts @@ -37,7 +37,7 @@ export const meta: Meta = { "https://raw.githubusercontent.com/gessig/base16-sandcastle-scheme/master/LICENSE", license_checksum: "8399d44b4d935b60be9fee0a76d7cc9a817b4f3f11574c9d6d1e8fd57e72ffdc", - } + }, }, url: "https://github.com/gessig/base16-sandcastle-scheme", } diff --git a/styles/src/themes/solarized.ts b/styles/src/themes/solarized.ts index 42306f68c3a6c4deea12006b88a320b596713ec1..1210c4380608e812d39dec0f36d6ec69dab37e9b 100644 --- a/styles/src/themes/solarized.ts +++ b/styles/src/themes/solarized.ts @@ -40,7 +40,7 @@ export const meta: Metadata = { "https://raw.githubusercontent.com/altercation/solarized/master/LICENSE", license_checksum: "494aefdabf86acce06bd63001ad8aedad4ee38da23509d3f917d95aa3368b9a6", - } + }, }, url: "https://github.com/altercation/solarized", } diff --git a/styles/src/themes/summercamp.ts b/styles/src/themes/summercamp.ts index e8d1bd40b2538b3904127e6699ef4236dd9d6b98..7df125e86606d299e52ffb07140f156744e086ce 100644 --- a/styles/src/themes/summercamp.ts +++ b/styles/src/themes/summercamp.ts @@ -39,6 +39,6 @@ export const meta: Meta = { "https://raw.githubusercontent.com/zoefiri/base16-sc/master/LICENSE", license_checksum: "fadcc834b7eaf2943800956600e8aeea4b495ecf6490f4c4b6c91556a90accaf", - } + }, }, } From 3952e98320799df81131a9772d2324935ee69825 Mon Sep 17 00:00:00 2001 From: Nate Butler Date: Thu, 9 Mar 2023 10:50:11 -0500 Subject: [PATCH 59/93] Remove Zed Pro theme --- styles/src/themes/staff/zed-pro.ts | 36 ------------------------------ 1 file changed, 36 deletions(-) delete mode 100644 styles/src/themes/staff/zed-pro.ts diff --git a/styles/src/themes/staff/zed-pro.ts b/styles/src/themes/staff/zed-pro.ts deleted file mode 100644 index 9b748be2991fc4dd49785537f07bdb0056436840..0000000000000000000000000000000000000000 --- a/styles/src/themes/staff/zed-pro.ts +++ /dev/null @@ -1,36 +0,0 @@ -import chroma from "chroma-js" -import { colorRamp, createColorScheme } from "../common/ramps" - -const name = "Zed Pro" -const author = "Nate Butler" -const url = "https://github.com/iamnbutler" -const license = { - type: "?", - url: "?", -} - -const ramps = { - neutral: chroma - .scale([ - "#101010", - "#1C1C1C", - "#212121", - "#2D2D2D", - "#B9B9B9", - "#DADADA", - "#E6E6E6", - "#FFFFFF", - ]) - .domain([0, 0.1, 0.2, 0.3, 0.7, 0.8, 0.9, 1]), - red: colorRamp(chroma("#DC604F")), - orange: colorRamp(chroma("#DE782F")), - yellow: colorRamp(chroma("#E0B750")), - green: colorRamp(chroma("#2A643D")), - cyan: colorRamp(chroma("#215050")), - blue: colorRamp(chroma("#2F6DB7")), - violet: colorRamp(chroma("#5874C1")), - magenta: colorRamp(chroma("#DE9AB8")), -} - -export const dark = createColorScheme(`${name} Dark`, false, ramps) -export const light = createColorScheme(`${name} Light`, true, ramps) From baff428de51407a842cd2e46400303af07aad088 Mon Sep 17 00:00:00 2001 From: Nate Butler Date: Thu, 9 Mar 2023 10:51:28 -0500 Subject: [PATCH 60/93] Re-add Ayu --- styles/src/themes/staff/ayu-mirage.ts | 31 ++++++++++++++++ styles/src/themes/staff/ayu.ts | 52 +++++++++++++++++++++++++++ 2 files changed, 83 insertions(+) create mode 100644 styles/src/themes/staff/ayu-mirage.ts create mode 100644 styles/src/themes/staff/ayu.ts diff --git a/styles/src/themes/staff/ayu-mirage.ts b/styles/src/themes/staff/ayu-mirage.ts new file mode 100644 index 0000000000000000000000000000000000000000..5b832699b46b984d9fd0fdaff223073613095aed --- /dev/null +++ b/styles/src/themes/staff/ayu-mirage.ts @@ -0,0 +1,31 @@ +import chroma from "chroma-js" +import { colorRamp, createColorScheme } from "../common/ramps" + +const name = "Ayu" +const author = "Konstantin Pschera " +const url = "https://github.com/ayu-theme/ayu-colors" +const license = { + type: "MIT", + url: "https://github.com/ayu-theme/ayu-colors/blob/master/license", +} + +export const dark = createColorScheme(`${name} Mirage`, false, { + neutral: chroma.scale([ + "#171B24", + "#1F2430", + "#242936", + "#707A8C", + "#8A9199", + "#CCCAC2", + "#D9D7CE", + "#F3F4F5", + ]), + red: colorRamp(chroma("#F28779")), + orange: colorRamp(chroma("#FFAD66")), + yellow: colorRamp(chroma("#FFD173")), + green: colorRamp(chroma("#D5FF80")), + cyan: colorRamp(chroma("#95E6CB")), + blue: colorRamp(chroma("#5CCFE6")), + violet: colorRamp(chroma("#D4BFFF")), + magenta: colorRamp(chroma("#F29E74")), +}) diff --git a/styles/src/themes/staff/ayu.ts b/styles/src/themes/staff/ayu.ts new file mode 100644 index 0000000000000000000000000000000000000000..24fcdb951b07aa3e7346c28566b26a549e388928 --- /dev/null +++ b/styles/src/themes/staff/ayu.ts @@ -0,0 +1,52 @@ +import chroma from "chroma-js" +import { colorRamp, createColorScheme } from "../common/ramps" + +const name = "Ayu" +const author = "Konstantin Pschera " +const url = "https://github.com/ayu-theme/ayu-colors" +const license = { + type: "MIT", + url: "https://github.com/ayu-theme/ayu-colors/blob/master/license", +} + +export const dark = createColorScheme(`${name} Dark`, false, { + neutral: chroma.scale([ + "#0F1419", + "#131721", + "#272D38", + "#3E4B59", + "#BFBDB6", + "#E6E1CF", + "#E6E1CF", + "#F3F4F5", + ]), + red: colorRamp(chroma("#F07178")), + orange: colorRamp(chroma("#FF8F40")), + yellow: colorRamp(chroma("#FFB454")), + green: colorRamp(chroma("#B8CC52")), + cyan: colorRamp(chroma("#95E6CB")), + blue: colorRamp(chroma("#59C2FF")), + violet: colorRamp(chroma("#D2A6FF")), + magenta: colorRamp(chroma("#E6B673")), +}) + +export const light = createColorScheme(`${name} Light`, true, { + neutral: chroma.scale([ + "#1A1F29", + "#242936", + "#5C6773", + "#828C99", + "#ABB0B6", + "#F8F9FA", + "#F3F4F5", + "#FAFAFA", + ]), + red: colorRamp(chroma("#F07178")), + orange: colorRamp(chroma("#FA8D3E")), + yellow: colorRamp(chroma("#F2AE49")), + green: colorRamp(chroma("#86B300")), + cyan: colorRamp(chroma("#4CBF99")), + blue: colorRamp(chroma("#36A3D9")), + violet: colorRamp(chroma("#A37ACC")), + magenta: colorRamp(chroma("#E6BA7E")), +}) From 4eb75f058f44b3d0cc8fd569cacd761d259ef82e Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Thu, 9 Mar 2023 12:00:58 -0800 Subject: [PATCH 61/93] Fix bug with wrong view ids being passed --- crates/workspace/src/dock.rs | 3 ++- crates/workspace/src/workspace.rs | 22 +++++++++++++++++----- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/crates/workspace/src/dock.rs b/crates/workspace/src/dock.rs index fd7638c5fbb492296a28e051177a8fd9699f3014..f5ee8cad51988f6662fd2106a60c89f2798ede88 100644 --- a/crates/workspace/src/dock.rs +++ b/crates/workspace/src/dock.rs @@ -181,6 +181,7 @@ pub struct Dock { impl Dock { pub fn new( + workspace_id: usize, default_item_factory: DockDefaultItemFactory, background_actions: BackgroundActions, cx: &mut ViewContext, @@ -189,7 +190,7 @@ impl Dock { let pane = cx.add_view(|cx| { Pane::new( - cx.handle().id(), + workspace_id, Some(position.anchor()), background_actions, cx, diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index ef14bfa2fe090ed90b66f309789d9af632712c63..b4b164ec3f6a3108c83c2c5e41b22eb6ed770ba3 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -606,9 +606,10 @@ impl Workspace { }) .detach(); - let workspace_view_id = cx.handle().id(); + let weak_handle = cx.weak_handle(); + let center_pane = - cx.add_view(|cx| Pane::new(workspace_view_id, None, background_actions, cx)); + cx.add_view(|cx| Pane::new(weak_handle.id(), None, background_actions, cx)); let pane_id = center_pane.id(); cx.subscribe(¢er_pane, move |this, _, event, cx| { this.handle_pane_event(pane_id, event, cx) @@ -616,7 +617,12 @@ impl Workspace { .detach(); cx.focus(¢er_pane); cx.emit(Event::PaneAdded(center_pane.clone())); - let dock = Dock::new(dock_default_factory, background_actions, cx); + let dock = Dock::new( + weak_handle.id(), + dock_default_factory, + background_actions, + cx, + ); let dock_pane = dock.pane().clone(); let fs = project.read(cx).fs().clone(); @@ -639,7 +645,6 @@ impl Workspace { } }); let handle = cx.handle(); - let weak_handle = cx.weak_handle(); // All leader updates are enqueued and then processed in a single task, so // that each asynchronous operation can be run in order. @@ -1440,7 +1445,14 @@ impl Workspace { } fn add_pane(&mut self, cx: &mut ViewContext) -> ViewHandle { - let pane = cx.add_view(|cx| Pane::new(cx.handle().id(), None, self.background_actions, cx)); + let pane = cx.add_view(|cx| { + Pane::new( + dbg!(self.weak_handle().id()), + None, + self.background_actions, + cx, + ) + }); let pane_id = pane.id(); cx.subscribe(&pane, move |this, _, event, cx| { this.handle_pane_event(pane_id, event, cx) From 718052bb726e9d4deb6d409e6758ddfd4c0f82e9 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Thu, 9 Mar 2023 13:02:25 -0800 Subject: [PATCH 62/93] Undo accidental indent change of hoverpopover.ts --- styles/src/styleTree/hoverPopover.ts | 78 ++++++++++++++-------------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/styles/src/styleTree/hoverPopover.ts b/styles/src/styleTree/hoverPopover.ts index a2a4467d7c5a9a08bc5cd589d4e9d129c7d8aa07..032c53112b27f9f6f47f378a23ef59a9ea40ac53 100644 --- a/styles/src/styleTree/hoverPopover.ts +++ b/styles/src/styleTree/hoverPopover.ts @@ -2,44 +2,44 @@ import { ColorScheme } from "../themes/common/colorScheme" import { background, border, text } from "./components" export default function HoverPopover(colorScheme: ColorScheme) { - let layer = colorScheme.middle - let baseContainer = { - background: background(layer), - cornerRadius: 8, - padding: { - left: 8, - right: 8, - top: 4, - bottom: 4, - }, - shadow: colorScheme.popoverShadow, - border: border(layer), - margin: { - left: -8, - }, - } + let layer = colorScheme.middle + let baseContainer = { + background: background(layer), + cornerRadius: 8, + padding: { + left: 8, + right: 8, + top: 4, + bottom: 4, + }, + shadow: colorScheme.popoverShadow, + border: border(layer), + margin: { + left: -8, + }, + } - return { - container: baseContainer, - infoContainer: { - ...baseContainer, - background: background(layer, "accent"), - border: border(layer, "accent"), - }, - warningContainer: { - ...baseContainer, - background: background(layer, "warning"), - border: border(layer, "warning"), - }, - errorContainer: { - ...baseContainer, - background: background(layer, "negative"), - border: border(layer, "negative"), - }, - block_style: { - padding: { top: 4 }, - }, - prose: text(layer, "sans", { size: "sm" }), - highlight: colorScheme.ramps.neutral(0.5).alpha(0.2).hex(), // TODO: blend was used here. Replace with something better - } + return { + container: baseContainer, + infoContainer: { + ...baseContainer, + background: background(layer, "accent"), + border: border(layer, "accent"), + }, + warningContainer: { + ...baseContainer, + background: background(layer, "warning"), + border: border(layer, "warning"), + }, + errorContainer: { + ...baseContainer, + background: background(layer, "negative"), + border: border(layer, "negative"), + }, + block_style: { + padding: { top: 4 }, + }, + prose: text(layer, "sans", { size: "sm" }), + highlight: colorScheme.ramps.neutral(0.5).alpha(0.2).hex(), // TODO: blend was used here. Replace with something better + } } From daed75096e98a4abdb95828e684d3e2089e050d3 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Thu, 9 Mar 2023 13:13:23 -0800 Subject: [PATCH 63/93] Fix editor test to clearly show trailing whitespace Adjsut default dock size to be a multiple of 16 --- crates/editor/src/editor_tests.rs | 16 ++++++++++------ styles/src/styleTree/workspace.ts | 2 +- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/crates/editor/src/editor_tests.rs b/crates/editor/src/editor_tests.rs index d73c3c87db324aac0a47158c55bf10f705e48695..4f61bde39877bb0fb7ba40c0000077cf75c9fe82 100644 --- a/crates/editor/src/editor_tests.rs +++ b/crates/editor/src/editor_tests.rs @@ -2353,12 +2353,16 @@ async fn test_clipboard(cx: &mut gpui::TestAppContext) { e.paste(&Paste, cx); e.handle_input(") ", cx); }); - cx.assert_editor_state(indoc! {" - ( one✅ - three - five ) ˇtwo one✅ four three six five ( one✅ - three - five ) ˇ"}); + cx.assert_editor_state( + &([ + "( one✅ ", + "three ", + "five ) ˇtwo one✅ four three six five ( one✅ ", + "three ", + "five ) ˇ", + ] + .join("\n")), + ); // Cut with three selections, one of which is full-line. cx.set_state(indoc! {" diff --git a/styles/src/styleTree/workspace.ts b/styles/src/styleTree/workspace.ts index d798a22e9d65b18140e3664b9cb7bb2858ee9569..1789b523e7fdbb93ecd9a3cc14604079a7dc57e5 100644 --- a/styles/src/styleTree/workspace.ts +++ b/styles/src/styleTree/workspace.ts @@ -282,7 +282,7 @@ export default function workspace(colorScheme: ColorScheme) { }, dock: { initialSizeRight: 640, - initialSizeBottom: 300, + initialSizeBottom: 304, wash_color: withOpacity(background(colorScheme.highest), 0.5), panel: { border: border(colorScheme.middle), From 20064b5629d347621447c343fb53abc074663926 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Thu, 9 Mar 2023 15:38:28 -0800 Subject: [PATCH 64/93] Add welcome to menu remove debug --- crates/workspace/src/workspace.rs | 10 ++-------- crates/zed/src/menus.rs | 1 + 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index b4b164ec3f6a3108c83c2c5e41b22eb6ed770ba3..609afded3325b97b8356c85b9b6955622a27e289 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -1445,14 +1445,8 @@ impl Workspace { } fn add_pane(&mut self, cx: &mut ViewContext) -> ViewHandle { - let pane = cx.add_view(|cx| { - Pane::new( - dbg!(self.weak_handle().id()), - None, - self.background_actions, - cx, - ) - }); + let pane = + cx.add_view(|cx| Pane::new(self.weak_handle().id(), None, self.background_actions, cx)); let pane_id = pane.id(); cx.subscribe(&pane, move |this, _, event, cx| { this.handle_pane_event(pane_id, event, cx) diff --git a/crates/zed/src/menus.rs b/crates/zed/src/menus.rs index d5fb94b2b698aa8260fb9eab7bd5dee8c6af7b4c..82422c5c19a848cf7533417dfe4e1f790353954c 100644 --- a/crates/zed/src/menus.rs +++ b/crates/zed/src/menus.rs @@ -139,6 +139,7 @@ pub fn menus() -> Vec> { MenuItem::separator(), MenuItem::action("View Telemetry", crate::OpenTelemetryLog), MenuItem::action("View Dependency Licenses", crate::OpenLicenses), + MenuItem::action("Show Welcome", workspace::Welcome), MenuItem::separator(), MenuItem::action( "Copy System Specs Into Clipboard", From 0384456e7d05526dc9b81124ae15a62ddaa6c9bd Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Thu, 9 Mar 2023 16:18:37 -0800 Subject: [PATCH 65/93] Change context matcher to search the entire stack --- crates/gpui/src/keymap_matcher/keymap_context.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/crates/gpui/src/keymap_matcher/keymap_context.rs b/crates/gpui/src/keymap_matcher/keymap_context.rs index bbf6bfc14bad820cd95c1525c5b673f8b8c04dcc..fbaaa5fbc5d1cb9f7f111fbdeb83a8447ee6992b 100644 --- a/crates/gpui/src/keymap_matcher/keymap_context.rs +++ b/crates/gpui/src/keymap_matcher/keymap_context.rs @@ -64,7 +64,13 @@ impl KeymapContextPredicate { pub fn eval(&self, contexts: &[KeymapContext]) -> bool { let Some(context) = contexts.first() else { return false }; match self { - Self::Identifier(name) => (&context.set).contains(name.as_str()), + Self::Identifier(name) => { + if (&context.set).contains(name.as_str()) { + true + } else { + self.eval(&contexts[1..]) + } + } Self::Equal(left, right) => context .map .get(left.as_str()) From 8ee25be7b93bab8a2a584eee89401bf6e341cf4f Mon Sep 17 00:00:00 2001 From: Nate Butler Date: Thu, 9 Mar 2023 20:18:29 -0500 Subject: [PATCH 66/93] Update empty pane styling Co-Authored-By: Mikayla Maki --- assets/icons/logo_256.svg | 41 ++++++++++++++++++++++++++++ assets/icons/logo_shadow_256.svg | 23 ++++++++++++++++ crates/theme/src/theme.rs | 2 ++ crates/workspace/src/pane.rs | 17 +++++++----- crates/zed/src/main.rs | 2 +- styles/src/styleTree/workspace.ts | 44 ++++++++++++++++++------------- 6 files changed, 104 insertions(+), 25 deletions(-) create mode 100644 assets/icons/logo_256.svg create mode 100644 assets/icons/logo_shadow_256.svg diff --git a/assets/icons/logo_256.svg b/assets/icons/logo_256.svg new file mode 100644 index 0000000000000000000000000000000000000000..4629600b4104cdbd18e545b967fa416d007c6675 --- /dev/null +++ b/assets/icons/logo_256.svg @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/icons/logo_shadow_256.svg b/assets/icons/logo_shadow_256.svg new file mode 100644 index 0000000000000000000000000000000000000000..6c331f43ab3f4f2c57b4569c212f5e423d8726d1 --- /dev/null +++ b/assets/icons/logo_shadow_256.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/crates/theme/src/theme.rs b/crates/theme/src/theme.rs index d331ca80a9fad31457fe648aaf7ae1b0e838d455..8ee58a8af2885907bc6e2c880bcef11344fa559c 100644 --- a/crates/theme/src/theme.rs +++ b/crates/theme/src/theme.rs @@ -76,6 +76,8 @@ pub struct Workspace { #[derive(Clone, Deserialize, Default)] pub struct BlankPaneStyle { pub logo: IconStyle, + pub logo_shadow: IconStyle, + pub logo_container: ContainerStyle, pub keyboard_hints: ContainerStyle, pub keyboard_hint: Interactive, pub keyboard_hint_width: f32, diff --git a/crates/workspace/src/pane.rs b/crates/workspace/src/pane.rs index abd410d875969a7d12611bae8d8e760ed9ade00e..6d20700bcc81aff330c6c61303f49a528009e5da 100644 --- a/crates/workspace/src/pane.rs +++ b/crates/workspace/src/pane.rs @@ -1429,7 +1429,6 @@ impl Pane { fn render_blank_pane(&mut self, theme: &Theme, cx: &mut RenderContext) -> ElementBox { let background = theme.workspace.background; - let keystroke_style = &theme.context_menu.item; let theme = &theme.workspace.blank_pane; Stack::new() .with_children([ @@ -1440,7 +1439,14 @@ impl Pane { Flex::column() .align_children_center() .with_children([ - theme::ui::icon(&theme.logo).aligned().boxed(), + Stack::new() + .with_children([ + theme::ui::icon(&theme.logo_shadow).aligned().boxed(), + theme::ui::icon(&theme.logo).aligned().boxed(), + ]) + .contained() + .with_style(theme.logo_container) + .boxed(), Flex::column() .with_children({ enum KeyboardHint {} @@ -1453,14 +1459,13 @@ impl Pane { idx, cx, move |state, cx| { + let style = keyboard_hint.style_for(state, false); theme::ui::keystroke_label_for( cx.window_id(), workspace_id, text, - &keyboard_hint.style_for(state, false), - &keystroke_style - .style_for(state, false) - .keystroke, + &style, + &style, hint_action, ) .boxed() diff --git a/crates/zed/src/main.rs b/crates/zed/src/main.rs index 2e2026309fca0da28ca878e9e8592589b945bd79..cbcd1aa1c602bc6aeecee68f7cb5946e1fff2f86 100644 --- a/crates/zed/src/main.rs +++ b/crates/zed/src/main.rs @@ -709,7 +709,7 @@ pub fn dock_default_item_factory( pub fn background_actions() -> &'static [(&'static str, &'static dyn Action)] { &[ ("Go to file", &file_finder::Toggle), - ("Open the command palette", &command_palette::Toggle), + ("Open command palette", &command_palette::Toggle), ("Focus the dock", &FocusDock), ("Open recent projects", &recent_projects::OpenRecent), ("Change your settings", &OpenSettings), diff --git a/styles/src/styleTree/workspace.ts b/styles/src/styleTree/workspace.ts index 1789b523e7fdbb93ecd9a3cc14604079a7dc57e5..984b6b5ed354bf4b9300581d4594b25614ea788b 100644 --- a/styles/src/styleTree/workspace.ts +++ b/styles/src/styleTree/workspace.ts @@ -42,38 +42,46 @@ export default function workspace(colorScheme: ColorScheme) { return { background: background(colorScheme.lowest), blankPane: { + logoContainer: { + width: 256, + height: 256, + }, logo: { - color: border(layer, "active").color, - icon: "icons/logo_96.svg", + color: withOpacity("#000000", colorScheme.isLight ? 0.6 : 0.8), + icon: "icons/logo_256.svg", dimensions: { - width: 272, - height: 272, - } + width: 256, + height: 256, + }, + }, + logoShadow: { + color: withOpacity(colorScheme.isLight ? "#FFFFFF" : colorScheme.lowest.base.default.background, colorScheme.isLight ? 1 : 0.6), + icon: "icons/logo_shadow_256.svg", + dimensions: { + width: 256, + height: 256, + }, }, keyboardHints: { margin: { - top: 32, - // bottom: -8. - }, - padding: { - top: 8, - left: 8, - right: 8, + top: 96, }, - background: background(colorScheme.lowest), - border: border(layer, "active"), cornerRadius: 4, }, keyboardHint: { ...text(layer, "sans", "variant", { size: "sm" }), - margin: { - bottom: 8 + padding: { + top: 3, + left: 8, + right: 8, + bottom: 3 }, + cornerRadius: 8, hover: { - ...text(layer, "sans", "hovered", { size: "sm" }), + ...text(layer, "sans", "active", { size: "sm" }), } }, - keyboardHintWidth: 272, + keyboardHintWidth: 320, }, joiningProjectAvatar: { cornerRadius: 40, From 01e3173ed0ca142f1f6bf149fefd218342b0d36b Mon Sep 17 00:00:00 2001 From: Julia Date: Thu, 9 Mar 2023 22:05:32 -0500 Subject: [PATCH 67/93] Preserve contacts popover editor contents when switching to search mode --- crates/collab_ui/src/contact_finder.rs | 14 ++++++++++++-- crates/collab_ui/src/contact_list.rs | 10 ++++++++++ crates/collab_ui/src/contacts_popover.rs | 22 ++++++++++++++-------- crates/picker/src/picker.rs | 5 +++++ 4 files changed, 41 insertions(+), 10 deletions(-) diff --git a/crates/collab_ui/src/contact_finder.rs b/crates/collab_ui/src/contact_finder.rs index 98f70e83f0ecf1eb3c312429a8461a35b028199e..ff783c6274855f2f117a8e7ac60451c25e506d0b 100644 --- a/crates/collab_ui/src/contact_finder.rs +++ b/crates/collab_ui/src/contact_finder.rs @@ -1,7 +1,7 @@ use client::{ContactRequestStatus, User, UserStore}; use gpui::{ - elements::*, AnyViewHandle, Entity, ModelHandle, MouseState, MutableAppContext, RenderContext, - Task, View, ViewContext, ViewHandle, + elements::*, AnyViewHandle, AppContext, Entity, ModelHandle, MouseState, MutableAppContext, + RenderContext, Task, View, ViewContext, ViewHandle, }; use picker::{Picker, PickerDelegate}; use settings::Settings; @@ -178,4 +178,14 @@ impl ContactFinder { selected_index: 0, } } + + pub fn editor_text(&self, cx: &AppContext) -> String { + self.picker.read(cx).query(cx) + } + + pub fn with_editor_text(self, editor_text: String, cx: &mut ViewContext) -> Self { + self.picker + .update(cx, |picker, cx| picker.set_query(editor_text, cx)); + self + } } diff --git a/crates/collab_ui/src/contact_list.rs b/crates/collab_ui/src/contact_list.rs index 3bb036d3366a4de8f4bb8e8253ae4470ce86edbc..dd6683292e3e76c711c97cad5432d66689ff69aa 100644 --- a/crates/collab_ui/src/contact_list.rs +++ b/crates/collab_ui/src/contact_list.rs @@ -294,6 +294,16 @@ impl ContactList { this } + pub fn editor_text(&self, cx: &AppContext) -> String { + self.filter_editor.read(cx).text(cx) + } + + pub fn with_editor_text(self, editor_text: String, cx: &mut ViewContext) -> Self { + self.filter_editor + .update(cx, |picker, cx| picker.set_text(editor_text, cx)); + self + } + fn remove_contact(&mut self, request: &RemoveContact, cx: &mut ViewContext) { let user_id = request.0; let user_store = self.user_store.clone(); diff --git a/crates/collab_ui/src/contacts_popover.rs b/crates/collab_ui/src/contacts_popover.rs index 0c67ef4c7c094a17758284bc5b2e8aeac8d30586..017950e6cc777543d7df8fdd98d40f0da8ed1e59 100644 --- a/crates/collab_ui/src/contacts_popover.rs +++ b/crates/collab_ui/src/contacts_popover.rs @@ -43,19 +43,23 @@ impl ContactsPopover { user_store, _subscription: None, }; - this.show_contact_list(cx); + this.show_contact_list(String::new(), cx); this } fn toggle_contact_finder(&mut self, _: &ToggleContactFinder, cx: &mut ViewContext) { match &self.child { - Child::ContactList(_) => self.show_contact_finder(cx), - Child::ContactFinder(_) => self.show_contact_list(cx), + Child::ContactList(list) => self.show_contact_finder(list.read(cx).editor_text(cx), cx), + Child::ContactFinder(finder) => { + self.show_contact_list(finder.read(cx).editor_text(cx), cx) + } } } - fn show_contact_finder(&mut self, cx: &mut ViewContext) { - let child = cx.add_view(|cx| ContactFinder::new(self.user_store.clone(), cx)); + fn show_contact_finder(&mut self, editor_text: String, cx: &mut ViewContext) { + let child = cx.add_view(|cx| { + ContactFinder::new(self.user_store.clone(), cx).with_editor_text(editor_text, cx) + }); cx.focus(&child); self._subscription = Some(cx.subscribe(&child, |_, _, event, cx| match event { crate::contact_finder::Event::Dismissed => cx.emit(Event::Dismissed), @@ -64,9 +68,11 @@ impl ContactsPopover { cx.notify(); } - fn show_contact_list(&mut self, cx: &mut ViewContext) { - let child = - cx.add_view(|cx| ContactList::new(self.project.clone(), self.user_store.clone(), cx)); + fn show_contact_list(&mut self, editor_text: String, cx: &mut ViewContext) { + let child = cx.add_view(|cx| { + ContactList::new(self.project.clone(), self.user_store.clone(), cx) + .with_editor_text(editor_text, cx) + }); cx.focus(&child); self._subscription = Some(cx.subscribe(&child, |_, _, event, cx| match event { crate::contact_list::Event::Dismissed => cx.emit(Event::Dismissed), diff --git a/crates/picker/src/picker.rs b/crates/picker/src/picker.rs index e4d062d575aa6a44909d0a757c766470987abb87..547e0160360acc9b4daa536191e68a2d2cd380d8 100644 --- a/crates/picker/src/picker.rs +++ b/crates/picker/src/picker.rs @@ -205,6 +205,11 @@ impl Picker { self.query_editor.read(cx).text(cx) } + pub fn set_query(&self, query: impl Into>, cx: &mut ViewContext) { + self.query_editor + .update(cx, |editor, cx| editor.set_text(query, cx)); + } + fn on_query_editor_event( &mut self, _: ViewHandle, From 648f0e5b7b6ec4185af1e2fe0439f727b0147305 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Thu, 9 Mar 2023 19:18:17 -0800 Subject: [PATCH 68/93] Remove new logo from style tree --- styles/src/styleTree/workspace.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/styles/src/styleTree/workspace.ts b/styles/src/styleTree/workspace.ts index 984b6b5ed354bf4b9300581d4594b25614ea788b..bebe87ce55c9ee15b7a13a49e6cffe9dba54cff6 100644 --- a/styles/src/styleTree/workspace.ts +++ b/styles/src/styleTree/workspace.ts @@ -48,7 +48,7 @@ export default function workspace(colorScheme: ColorScheme) { }, logo: { color: withOpacity("#000000", colorScheme.isLight ? 0.6 : 0.8), - icon: "icons/logo_256.svg", + icon: "icons/logo_96.svg", dimensions: { width: 256, height: 256, @@ -56,7 +56,7 @@ export default function workspace(colorScheme: ColorScheme) { }, logoShadow: { color: withOpacity(colorScheme.isLight ? "#FFFFFF" : colorScheme.lowest.base.default.background, colorScheme.isLight ? 1 : 0.6), - icon: "icons/logo_shadow_256.svg", + icon: "icons/logo_96.svg", dimensions: { width: 256, height: 256, From 9dc608dc4b4dedd11638d7cb472456e77d9272b6 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Thu, 9 Mar 2023 19:32:09 -0800 Subject: [PATCH 69/93] Switch from changing the meaning of the predicate to adding an additional match_dispatch_path_context API for UI elements --- crates/gpui/src/app.rs | 4 ++-- crates/gpui/src/keymap_matcher/binding.rs | 9 +++++++++ crates/gpui/src/keymap_matcher/keymap_context.rs | 8 +------- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/crates/gpui/src/app.rs b/crates/gpui/src/app.rs index 31563010b723d88b4f834084fba91cb3ecd9a15c..ab88a39a9aac7e4a705bfc7f4df2c668d08b6f83 100644 --- a/crates/gpui/src/app.rs +++ b/crates/gpui/src/app.rs @@ -1248,7 +1248,7 @@ impl MutableAppContext { self.keystroke_matcher .bindings_for_action_type(action.as_any().type_id()) .find_map(|b| { - if b.match_context(&contexts) { + if b.match_dispatch_path_context(&contexts) { Some(b.keystrokes().into()) } else { None @@ -1283,7 +1283,7 @@ impl MutableAppContext { deserialize("{}").ok()?, self.keystroke_matcher .bindings_for_action_type(*type_id) - .filter(|b| b.match_context(&contexts)) + .filter(|b| b.match_dispatch_path_context(&contexts)) .collect(), )) } else { diff --git a/crates/gpui/src/keymap_matcher/binding.rs b/crates/gpui/src/keymap_matcher/binding.rs index c1cfd14e82d8d3e3235a7a2c3e7d507cd78d9648..1b0217b5ff141751a8b2a35ffa37e93774f67c93 100644 --- a/crates/gpui/src/keymap_matcher/binding.rs +++ b/crates/gpui/src/keymap_matcher/binding.rs @@ -42,6 +42,15 @@ impl Binding { .unwrap_or(true) } + pub fn match_dispatch_path_context(&self, contexts: &[KeymapContext]) -> bool { + for i in 0..contexts.len() { + if self.match_context(&contexts[i..]) { + return true; + } + } + false + } + pub fn match_keys_and_context( &self, pending_keystrokes: &Vec, diff --git a/crates/gpui/src/keymap_matcher/keymap_context.rs b/crates/gpui/src/keymap_matcher/keymap_context.rs index fbaaa5fbc5d1cb9f7f111fbdeb83a8447ee6992b..bbf6bfc14bad820cd95c1525c5b673f8b8c04dcc 100644 --- a/crates/gpui/src/keymap_matcher/keymap_context.rs +++ b/crates/gpui/src/keymap_matcher/keymap_context.rs @@ -64,13 +64,7 @@ impl KeymapContextPredicate { pub fn eval(&self, contexts: &[KeymapContext]) -> bool { let Some(context) = contexts.first() else { return false }; match self { - Self::Identifier(name) => { - if (&context.set).contains(name.as_str()) { - true - } else { - self.eval(&contexts[1..]) - } - } + Self::Identifier(name) => (&context.set).contains(name.as_str()), Self::Equal(left, right) => context .map .get(left.as_str()) From 8b7273e46e7cdf2206491e152083b2f028af805b Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 10 Mar 2023 09:54:57 +0100 Subject: [PATCH 70/93] Increase the amount of max connections to the database --- crates/collab/.env.toml | 1 + crates/collab/k8s/environments/preview.sh | 1 + crates/collab/k8s/environments/production.sh | 1 + crates/collab/k8s/environments/staging.sh | 1 + crates/collab/k8s/manifest.template.yml | 2 ++ crates/collab/src/lib.rs | 3 ++- 6 files changed, 8 insertions(+), 1 deletion(-) diff --git a/crates/collab/.env.toml b/crates/collab/.env.toml index b4a6694e5e6578e771406d6947c2c4ad8d2efb0a..01866012ea8a14c94835d0662318d3f8c4df67f5 100644 --- a/crates/collab/.env.toml +++ b/crates/collab/.env.toml @@ -1,4 +1,5 @@ DATABASE_URL = "postgres://postgres@localhost/zed" +DATABASE_MAX_CONNECTIONS = 5 HTTP_PORT = 8080 API_TOKEN = "secret" INVITE_LINK_PREFIX = "http://localhost:3000/invites/" diff --git a/crates/collab/k8s/environments/preview.sh b/crates/collab/k8s/environments/preview.sh index 4d9dd849e96f9bb5fc672beb0b7547c6246358de..132a1ef53c2b84bb97659b15800888b195b9de65 100644 --- a/crates/collab/k8s/environments/preview.sh +++ b/crates/collab/k8s/environments/preview.sh @@ -1,3 +1,4 @@ ZED_ENVIRONMENT=preview RUST_LOG=info INVITE_LINK_PREFIX=https://zed.dev/invites/ +DATABASE_MAX_CONNECTIONS=10 diff --git a/crates/collab/k8s/environments/production.sh b/crates/collab/k8s/environments/production.sh index 83af6630c2e0a52b915c2a1ddb07778e60e16a4e..cb1d4b4de712864003c711dd8b46123b31fa5d5f 100644 --- a/crates/collab/k8s/environments/production.sh +++ b/crates/collab/k8s/environments/production.sh @@ -1,3 +1,4 @@ ZED_ENVIRONMENT=production RUST_LOG=info INVITE_LINK_PREFIX=https://zed.dev/invites/ +DATABASE_MAX_CONNECTIONS=85 diff --git a/crates/collab/k8s/environments/staging.sh b/crates/collab/k8s/environments/staging.sh index 82d799e2bc200c44a27a5ce7712fc1106b15970f..b9689ccb19390b412f4a7df9e8fee2e744b0479c 100644 --- a/crates/collab/k8s/environments/staging.sh +++ b/crates/collab/k8s/environments/staging.sh @@ -1,3 +1,4 @@ ZED_ENVIRONMENT=staging RUST_LOG=info INVITE_LINK_PREFIX=https://staging.zed.dev/invites/ +DATABASE_MAX_CONNECTIONS=5 diff --git a/crates/collab/k8s/manifest.template.yml b/crates/collab/k8s/manifest.template.yml index b73070536f1d5d7104afc710cd57e42dba991650..75c7aa989d9797f28c57d1ee1f5cab90b28bcfeb 100644 --- a/crates/collab/k8s/manifest.template.yml +++ b/crates/collab/k8s/manifest.template.yml @@ -80,6 +80,8 @@ spec: secretKeyRef: name: database key: url + - name: DATABASE_MAX_CONNECTIONS + value: ${DATABASE_MAX_CONNECTIONS} - name: API_TOKEN valueFrom: secretKeyRef: diff --git a/crates/collab/src/lib.rs b/crates/collab/src/lib.rs index 1a83193bdfc3455fe23791b19e1b18b3e5673aaa..8c99a5ea0f5623ce5e86938587427de0d616f77c 100644 --- a/crates/collab/src/lib.rs +++ b/crates/collab/src/lib.rs @@ -91,6 +91,7 @@ impl std::error::Error for Error {} pub struct Config { pub http_port: u16, pub database_url: String, + pub database_max_connections: u32, pub api_token: String, pub invite_link_prefix: String, pub live_kit_server: Option, @@ -116,7 +117,7 @@ pub struct AppState { impl AppState { pub async fn new(config: Config) -> Result> { let mut db_options = db::ConnectOptions::new(config.database_url.clone()); - db_options.max_connections(5); + db_options.max_connections(config.database_max_connections); let db = Database::new(db_options).await?; let live_kit_client = if let Some(((server, key), secret)) = config .live_kit_server From 221bb54e48610ea946f5436603e3ebdcba4c9f28 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 10 Mar 2023 11:41:13 +0100 Subject: [PATCH 71/93] Introduce a new `TryFutureExt::unwrap` method --- Cargo.lock | 1 + crates/client/src/telemetry.rs | 4 +- crates/collab_ui/src/contact_finder.rs | 2 +- crates/journal/Cargo.toml | 1 + crates/journal/src/journal.rs | 2 +- crates/lsp/src/lsp.rs | 191 ++++++++++++++----------- crates/project/src/project.rs | 2 +- crates/util/src/util.rs | 40 +++++- 8 files changed, 151 insertions(+), 92 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cfd27bbdd0afc23b68e26379a1c7fb09db56986c..87e32ed97de3e024cb144ecaa5bec866857970d3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3157,6 +3157,7 @@ dependencies = [ name = "journal" version = "0.1.0" dependencies = [ + "anyhow", "chrono", "dirs 4.0.0", "editor", diff --git a/crates/client/src/telemetry.rs b/crates/client/src/telemetry.rs index 748eb48f7e27368588534266fe34e9183cb01b78..9d486619d255dd7ab214a145f7f31162dd4a9c36 100644 --- a/crates/client/src/telemetry.rs +++ b/crates/client/src/telemetry.rs @@ -224,7 +224,7 @@ impl Telemetry { .header("Content-Type", "application/json") .body(json_bytes.into())?; this.http_client.send(request).await?; - Ok(()) + anyhow::Ok(()) } .log_err(), ) @@ -320,7 +320,7 @@ impl Telemetry { .header("Content-Type", "application/json") .body(json_bytes.into())?; this.http_client.send(request).await?; - Ok(()) + anyhow::Ok(()) } .log_err(), ) diff --git a/crates/collab_ui/src/contact_finder.rs b/crates/collab_ui/src/contact_finder.rs index ff783c6274855f2f117a8e7ac60451c25e506d0b..3b93414e1f45bed398d45cc59362406fd0744196 100644 --- a/crates/collab_ui/src/contact_finder.rs +++ b/crates/collab_ui/src/contact_finder.rs @@ -68,7 +68,7 @@ impl PickerDelegate for ContactFinder { this.potential_contacts = potential_contacts.into(); cx.notify(); }); - Ok(()) + anyhow::Ok(()) } .log_err() .await; diff --git a/crates/journal/Cargo.toml b/crates/journal/Cargo.toml index b532397dd1ddcbc59bb24a21f3da0d6d61552c4c..a2656ad219f0c30916825f8776b667a3cf5add92 100644 --- a/crates/journal/Cargo.toml +++ b/crates/journal/Cargo.toml @@ -13,6 +13,7 @@ editor = { path = "../editor" } gpui = { path = "../gpui" } util = { path = "../util" } workspace = { path = "../workspace" } +anyhow = "1.0" chrono = "0.4" dirs = "4.0" log = { version = "0.4.16", features = ["kv_unstable_serde"] } diff --git a/crates/journal/src/journal.rs b/crates/journal/src/journal.rs index 76a56af93d8c4cdc45a60a31e4ebc007899f61cc..1ad97e61b1175c69cd802098044838db774e27fa 100644 --- a/crates/journal/src/journal.rs +++ b/crates/journal/src/journal.rs @@ -73,7 +73,7 @@ pub fn new_journal_entry(app_state: Arc, cx: &mut MutableAppContext) { } } - Ok(()) + anyhow::Ok(()) } .log_err() }) diff --git a/crates/lsp/src/lsp.rs b/crates/lsp/src/lsp.rs index 6982445982fe0383460b79983e60a35c693d4705..81568b9e3e449b4a922d6c7e64dfe0df309fbb6c 100644 --- a/crates/lsp/src/lsp.rs +++ b/crates/lsp/src/lsp.rs @@ -160,15 +160,13 @@ impl LanguageServer { server: Option, root_path: &Path, cx: AsyncAppContext, - mut on_unhandled_notification: F, + on_unhandled_notification: F, ) -> Self where Stdin: AsyncWrite + Unpin + Send + 'static, Stdout: AsyncRead + Unpin + Send + 'static, F: FnMut(AnyNotification) + 'static + Send, { - let mut stdin = BufWriter::new(stdin); - let mut stdout = BufReader::new(stdout); let (outbound_tx, outbound_rx) = channel::unbounded::>(); let notification_handlers = Arc::new(Mutex::new(HashMap::<_, NotificationHandler>::default())); @@ -177,89 +175,19 @@ impl LanguageServer { let input_task = cx.spawn(|cx| { let notification_handlers = notification_handlers.clone(); let response_handlers = response_handlers.clone(); - async move { - let _clear_response_handlers = util::defer({ - let response_handlers = response_handlers.clone(); - move || { - response_handlers.lock().take(); - } - }); - let mut buffer = Vec::new(); - loop { - buffer.clear(); - stdout.read_until(b'\n', &mut buffer).await?; - stdout.read_until(b'\n', &mut buffer).await?; - let message_len: usize = std::str::from_utf8(&buffer)? - .strip_prefix(CONTENT_LEN_HEADER) - .ok_or_else(|| anyhow!("invalid header"))? - .trim_end() - .parse()?; - - buffer.resize(message_len, 0); - stdout.read_exact(&mut buffer).await?; - log::trace!("incoming message:{}", String::from_utf8_lossy(&buffer)); - - if let Ok(msg) = serde_json::from_slice::(&buffer) { - if let Some(handler) = notification_handlers.lock().get_mut(msg.method) { - handler(msg.id, msg.params.get(), cx.clone()); - } else { - on_unhandled_notification(msg); - } - } else if let Ok(AnyResponse { - id, error, result, .. - }) = serde_json::from_slice(&buffer) - { - if let Some(handler) = response_handlers - .lock() - .as_mut() - .and_then(|handlers| handlers.remove(&id)) - { - if let Some(error) = error { - handler(Err(error)); - } else if let Some(result) = result { - handler(Ok(result.get())); - } else { - handler(Ok("null")); - } - } - } else { - warn!( - "Failed to deserialize message:\n{}", - std::str::from_utf8(&buffer)? - ); - } - - // Don't starve the main thread when receiving lots of messages at once. - smol::future::yield_now().await; - } - } + Self::handle_input( + stdout, + on_unhandled_notification, + notification_handlers, + response_handlers, + cx, + ) .log_err() }); let (output_done_tx, output_done_rx) = barrier::channel(); let output_task = cx.background().spawn({ let response_handlers = response_handlers.clone(); - async move { - let _clear_response_handlers = util::defer({ - let response_handlers = response_handlers.clone(); - move || { - response_handlers.lock().take(); - } - }); - let mut content_len_buffer = Vec::new(); - while let Ok(message) = outbound_rx.recv().await { - log::trace!("outgoing message:{}", String::from_utf8_lossy(&message)); - content_len_buffer.clear(); - write!(content_len_buffer, "{}", message.len()).unwrap(); - stdin.write_all(CONTENT_LEN_HEADER.as_bytes()).await?; - stdin.write_all(&content_len_buffer).await?; - stdin.write_all("\r\n\r\n".as_bytes()).await?; - stdin.write_all(&message).await?; - stdin.flush().await?; - } - drop(output_done_tx); - Ok(()) - } - .log_err() + Self::handle_output(stdin, outbound_rx, output_done_tx, response_handlers).log_err() }); Self { @@ -278,6 +206,105 @@ impl LanguageServer { } } + async fn handle_input( + stdout: Stdout, + mut on_unhandled_notification: F, + notification_handlers: Arc>>, + response_handlers: Arc>>>, + cx: AsyncAppContext, + ) -> anyhow::Result<()> + where + Stdout: AsyncRead + Unpin + Send + 'static, + F: FnMut(AnyNotification) + 'static + Send, + { + let mut stdout = BufReader::new(stdout); + let _clear_response_handlers = util::defer({ + let response_handlers = response_handlers.clone(); + move || { + response_handlers.lock().take(); + } + }); + let mut buffer = Vec::new(); + loop { + buffer.clear(); + stdout.read_until(b'\n', &mut buffer).await?; + stdout.read_until(b'\n', &mut buffer).await?; + let message_len: usize = std::str::from_utf8(&buffer)? + .strip_prefix(CONTENT_LEN_HEADER) + .ok_or_else(|| anyhow!("invalid header"))? + .trim_end() + .parse()?; + + buffer.resize(message_len, 0); + stdout.read_exact(&mut buffer).await?; + log::trace!("incoming message:{}", String::from_utf8_lossy(&buffer)); + + if let Ok(msg) = serde_json::from_slice::(&buffer) { + if let Some(handler) = notification_handlers.lock().get_mut(msg.method) { + handler(msg.id, msg.params.get(), cx.clone()); + } else { + on_unhandled_notification(msg); + } + } else if let Ok(AnyResponse { + id, error, result, .. + }) = serde_json::from_slice(&buffer) + { + if let Some(handler) = response_handlers + .lock() + .as_mut() + .and_then(|handlers| handlers.remove(&id)) + { + if let Some(error) = error { + handler(Err(error)); + } else if let Some(result) = result { + handler(Ok(result.get())); + } else { + handler(Ok("null")); + } + } + } else { + warn!( + "Failed to deserialize message:\n{}", + std::str::from_utf8(&buffer)? + ); + } + + // Don't starve the main thread when receiving lots of messages at once. + smol::future::yield_now().await; + } + } + + async fn handle_output( + stdin: Stdin, + outbound_rx: channel::Receiver>, + output_done_tx: barrier::Sender, + response_handlers: Arc>>>, + ) -> anyhow::Result<()> + where + Stdin: AsyncWrite + Unpin + Send + 'static, + { + let mut stdin = BufWriter::new(stdin); + let _clear_response_handlers = util::defer({ + let response_handlers = response_handlers.clone(); + move || { + response_handlers.lock().take(); + } + }); + let mut content_len_buffer = Vec::new(); + while let Ok(message) = outbound_rx.recv().await { + log::trace!("outgoing message:{}", String::from_utf8_lossy(&message)); + content_len_buffer.clear(); + write!(content_len_buffer, "{}", message.len()).unwrap(); + stdin.write_all(CONTENT_LEN_HEADER.as_bytes()).await?; + stdin.write_all(&content_len_buffer).await?; + stdin.write_all("\r\n\r\n".as_bytes()).await?; + stdin.write_all(&message).await?; + stdin.flush().await?; + } + drop(output_done_tx); + Ok(()) + } + /// Initializes a language server. /// Note that `options` is used directly to construct [`InitializeParams`], /// which is why it is owned. @@ -389,7 +416,7 @@ impl LanguageServer { output_done.recv().await; log::debug!("language server shutdown finished"); drop(tasks); - Ok(()) + anyhow::Ok(()) } .log_err(), ) diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index 2ebea8d07dad811a378a065a7f666caaf594c6d3..a970c7bb19296ea6dacb0480daf73e57680bea86 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -5831,7 +5831,7 @@ impl Project { })?; } - Ok(()) + anyhow::Ok(()) } .log_err(), ) diff --git a/crates/util/src/util.rs b/crates/util/src/util.rs index 5ecf889f9b1a016a86987827390831b37efe8d1c..3824312a4fa9ec0d9993063c855b37bc55c3121c 100644 --- a/crates/util/src/util.rs +++ b/crates/util/src/util.rs @@ -124,11 +124,15 @@ pub trait TryFutureExt { fn warn_on_err(self) -> LogErrorFuture where Self: Sized; + fn unwrap(self) -> UnwrapFuture + where + Self: Sized; } -impl TryFutureExt for F +impl TryFutureExt for F where - F: Future>, + F: Future>, + E: std::fmt::Debug, { fn log_err(self) -> LogErrorFuture where @@ -143,17 +147,25 @@ where { LogErrorFuture(self, log::Level::Warn) } + + fn unwrap(self) -> UnwrapFuture + where + Self: Sized, + { + UnwrapFuture(self) + } } pub struct LogErrorFuture(F, log::Level); -impl Future for LogErrorFuture +impl Future for LogErrorFuture where - F: Future>, + F: Future>, + E: std::fmt::Debug, { type Output = Option; - fn poll(self: std::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll { let level = self.1; let inner = unsafe { Pin::new_unchecked(&mut self.get_unchecked_mut().0) }; match inner.poll(cx) { @@ -169,6 +181,24 @@ where } } +pub struct UnwrapFuture(F); + +impl Future for UnwrapFuture +where + F: Future>, + E: std::fmt::Debug, +{ + type Output = T; + + fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll { + let inner = unsafe { Pin::new_unchecked(&mut self.get_unchecked_mut().0) }; + match inner.poll(cx) { + Poll::Ready(result) => Poll::Ready(result.unwrap()), + Poll::Pending => Poll::Pending, + } + } +} + struct Defer(Option); impl Drop for Defer { From 7a600e7a65855148d6fd50478abd2ecbd1a08bf5 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 10 Mar 2023 12:17:47 +0100 Subject: [PATCH 72/93] Allow waiting for language to be loaded in `LanguageRegistry` APIs --- crates/editor/src/hover_popover.rs | 11 +-- crates/feedback/src/feedback_editor.rs | 33 ++++--- crates/language/src/buffer_tests.rs | 54 +++++++---- crates/language/src/language.rs | 51 +++++++--- crates/language/src/syntax_map.rs | 30 +++--- crates/project/src/project.rs | 22 ++++- crates/zed/src/zed.rs | 126 ++++++++++++++----------- 7 files changed, 201 insertions(+), 126 deletions(-) diff --git a/crates/editor/src/hover_popover.rs b/crates/editor/src/hover_popover.rs index f92b07da1dd49ef4de90e7bb9fc9a00ee4993fd4..1a23a02efc3fd93cd6c73571f84f93449f588de4 100644 --- a/crates/editor/src/hover_popover.rs +++ b/crates/editor/src/hover_popover.rs @@ -1,3 +1,4 @@ +use futures::FutureExt; use gpui::{ actions, elements::{Flex, MouseEventHandler, Padding, Text}, @@ -327,12 +328,10 @@ impl InfoPopover { MouseEventHandler::::new(0, cx, |_, cx| { let mut flex = Flex::new(Axis::Vertical).scrollable::(1, None, cx); flex.extend(self.contents.iter().map(|content| { - let project = self.project.read(cx); - if let Some(language) = content - .language - .clone() - .and_then(|language| project.languages().language_for_name(&language)) - { + let languages = self.project.read(cx).languages(); + if let Some(language) = content.language.clone().and_then(|language| { + languages.language_for_name(&language).now_or_never()?.ok() + }) { let runs = language .highlight_text(&content.text.as_str().into(), 0..content.text.len()); diff --git a/crates/feedback/src/feedback_editor.rs b/crates/feedback/src/feedback_editor.rs index e30b85170c5fd7f128948d7622c166b03b30522d..8b12e859e64eb93e070fc1cfa196f87431c73244 100644 --- a/crates/feedback/src/feedback_editor.rs +++ b/crates/feedback/src/feedback_editor.rs @@ -20,6 +20,7 @@ use postage::prelude::Stream; use project::Project; use serde::Serialize; +use util::ResultExt; use workspace::{ item::{Item, ItemHandle}, searchable::{SearchableItem, SearchableItemHandle}, @@ -200,24 +201,28 @@ impl FeedbackEditor { impl FeedbackEditor { pub fn deploy( system_specs: SystemSpecs, - workspace: &mut Workspace, + _: &mut Workspace, app_state: Arc, cx: &mut ViewContext, ) { - workspace - .with_local_workspace(&app_state, cx, |workspace, cx| { - let project = workspace.project().clone(); - let markdown_language = project.read(cx).languages().language_for_name("Markdown"); - let buffer = project - .update(cx, |project, cx| { - project.create_buffer("", markdown_language, cx) + let markdown = app_state.languages.language_for_name("Markdown"); + cx.spawn(|workspace, mut cx| async move { + let markdown = markdown.await.log_err(); + workspace + .update(&mut cx, |workspace, cx| { + workspace.with_local_workspace(&app_state, cx, |workspace, cx| { + let project = workspace.project().clone(); + let buffer = project + .update(cx, |project, cx| project.create_buffer("", markdown, cx)) + .expect("creating buffers on a local workspace always succeeds"); + let feedback_editor = cx + .add_view(|cx| FeedbackEditor::new(system_specs, project, buffer, cx)); + workspace.add_item(Box::new(feedback_editor), cx); }) - .expect("creating buffers on a local workspace always succeeds"); - let feedback_editor = - cx.add_view(|cx| FeedbackEditor::new(system_specs, project, buffer, cx)); - workspace.add_item(Box::new(feedback_editor), cx); - }) - .detach(); + }) + .await; + }) + .detach(); } } diff --git a/crates/language/src/buffer_tests.rs b/crates/language/src/buffer_tests.rs index e98edbb2d32c1c6bf06a1f250e6ecb8b41a52b02..3e65ec3120445bb69604c056b200d4b8f66b6863 100644 --- a/crates/language/src/buffer_tests.rs +++ b/crates/language/src/buffer_tests.rs @@ -80,31 +80,49 @@ fn test_select_language() { // matching file extension assert_eq!( - registry.language_for_path("zed/lib.rs").map(|l| l.name()), + registry + .language_for_path("zed/lib.rs") + .now_or_never() + .and_then(|l| Some(l.ok()?.name())), Some("Rust".into()) ); assert_eq!( - registry.language_for_path("zed/lib.mk").map(|l| l.name()), + registry + .language_for_path("zed/lib.mk") + .now_or_never() + .and_then(|l| Some(l.ok()?.name())), Some("Make".into()) ); // matching filename assert_eq!( - registry.language_for_path("zed/Makefile").map(|l| l.name()), + registry + .language_for_path("zed/Makefile") + .now_or_never() + .and_then(|l| Some(l.ok()?.name())), Some("Make".into()) ); // matching suffix that is not the full file extension or filename assert_eq!( - registry.language_for_path("zed/cars").map(|l| l.name()), + registry + .language_for_path("zed/cars") + .now_or_never() + .and_then(|l| Some(l.ok()?.name())), None ); assert_eq!( - registry.language_for_path("zed/a.cars").map(|l| l.name()), + registry + .language_for_path("zed/a.cars") + .now_or_never() + .and_then(|l| Some(l.ok()?.name())), None ); assert_eq!( - registry.language_for_path("zed/sumk").map(|l| l.name()), + registry + .language_for_path("zed/sumk") + .now_or_never() + .and_then(|l| Some(l.ok()?.name())), None ); } @@ -666,14 +684,14 @@ fn test_enclosing_bracket_ranges(cx: &mut MutableAppContext) { indoc! {" mod x { moˇd y { - + } } let foo = 1;"}, vec![indoc! {" mod x «{» mod y { - + } «}» let foo = 1;"}], @@ -683,7 +701,7 @@ fn test_enclosing_bracket_ranges(cx: &mut MutableAppContext) { indoc! {" mod x { mod y ˇ{ - + } } let foo = 1;"}, @@ -691,14 +709,14 @@ fn test_enclosing_bracket_ranges(cx: &mut MutableAppContext) { indoc! {" mod x «{» mod y { - + } «}» let foo = 1;"}, indoc! {" mod x { mod y «{» - + «}» } let foo = 1;"}, @@ -709,7 +727,7 @@ fn test_enclosing_bracket_ranges(cx: &mut MutableAppContext) { indoc! {" mod x { mod y { - + }ˇ } let foo = 1;"}, @@ -717,14 +735,14 @@ fn test_enclosing_bracket_ranges(cx: &mut MutableAppContext) { indoc! {" mod x «{» mod y { - + } «}» let foo = 1;"}, indoc! {" mod x { mod y «{» - + «}» } let foo = 1;"}, @@ -735,14 +753,14 @@ fn test_enclosing_bracket_ranges(cx: &mut MutableAppContext) { indoc! {" mod x { mod y { - + } ˇ} let foo = 1;"}, vec![indoc! {" mod x «{» mod y { - + } «}» let foo = 1;"}], @@ -752,7 +770,7 @@ fn test_enclosing_bracket_ranges(cx: &mut MutableAppContext) { indoc! {" mod x { mod y { - + } } let fˇoo = 1;"}, @@ -764,7 +782,7 @@ fn test_enclosing_bracket_ranges(cx: &mut MutableAppContext) { indoc! {" mod x { mod y { - + } } let foo = 1;ˇ"}, diff --git a/crates/language/src/language.rs b/crates/language/src/language.rs index 983bc58f762e24a01fa1d9ff1beeca7585dda1e8..30fc5db56329d8621f0c52d506dbabce2cd428c3 100644 --- a/crates/language/src/language.rs +++ b/crates/language/src/language.rs @@ -13,8 +13,9 @@ use async_trait::async_trait; use client::http::HttpClient; use collections::HashMap; use futures::{ + channel::oneshot, future::{BoxFuture, Shared}, - FutureExt, TryFutureExt, + FutureExt, TryFutureExt as _, }; use gpui::{executor::Background, MutableAppContext, Task}; use highlight_map::HighlightMap; @@ -43,7 +44,7 @@ use syntax_map::SyntaxSnapshot; use theme::{SyntaxTheme, Theme}; use tree_sitter::{self, Query}; use unicase::UniCase; -use util::ResultExt; +use util::{ResultExt, TryFutureExt as _, UnwrapFuture}; #[cfg(any(test, feature = "test-support"))] use futures::channel::mpsc; @@ -484,7 +485,7 @@ impl LanguageRegistry { let (lsp_binary_statuses_tx, lsp_binary_statuses_rx) = async_broadcast::broadcast(16); Self { language_server_download_dir: None, - languages: Default::default(), + languages: RwLock::new(vec![PLAIN_TEXT.clone()]), available_languages: Default::default(), lsp_binary_statuses_tx, lsp_binary_statuses_rx, @@ -568,12 +569,18 @@ impl LanguageRegistry { self.language_server_download_dir = Some(path.into()); } - pub fn language_for_name(self: &Arc, name: &str) -> Option> { + pub fn language_for_name( + self: &Arc, + name: &str, + ) -> UnwrapFuture>>> { let name = UniCase::new(name); self.get_or_load_language(|config| UniCase::new(config.name.as_ref()) == name) } - pub fn language_for_name_or_extension(self: &Arc, string: &str) -> Option> { + pub fn language_for_name_or_extension( + self: &Arc, + string: &str, + ) -> UnwrapFuture>>> { let string = UniCase::new(string); self.get_or_load_language(|config| { UniCase::new(config.name.as_ref()) == string @@ -584,7 +591,10 @@ impl LanguageRegistry { }) } - pub fn language_for_path(self: &Arc, path: impl AsRef) -> Option> { + pub fn language_for_path( + self: &Arc, + path: impl AsRef, + ) -> UnwrapFuture>>> { let path = path.as_ref(); let filename = path.file_name().and_then(|name| name.to_str()); let extension = path.extension().and_then(|name| name.to_str()); @@ -600,17 +610,17 @@ impl LanguageRegistry { fn get_or_load_language( self: &Arc, callback: impl Fn(&LanguageConfig) -> bool, - ) -> Option> { + ) -> UnwrapFuture>>> { + let (tx, rx) = oneshot::channel(); + if let Some(language) = self .languages .read() .iter() .find(|language| callback(&language.config)) { - return Some(language.clone()); - } - - if let Some(executor) = self.executor.clone() { + let _ = tx.send(Ok(language.clone())); + } else if let Some(executor) = self.executor.clone() { let mut available_languages = self.available_languages.write(); if let Some(ix) = available_languages.iter().position(|l| callback(&l.config)) { @@ -625,18 +635,29 @@ impl LanguageRegistry { .with_lsp_adapter(language.lsp_adapter) .await; match language.with_queries(queries) { - Ok(language) => this.add(Arc::new(language)), + Ok(language) => { + let language = Arc::new(language); + this.add(language.clone()); + let _ = tx.send(Ok(language)); + } Err(err) => { - log::error!("failed to load language {}: {}", name, err); - return; + let _ = tx.send(Err(anyhow!( + "failed to load language {}: {}", + name, + err + ))); } }; }) .detach(); + } else { + let _ = tx.send(Err(anyhow!("language not found"))); } + } else { + let _ = tx.send(Err(anyhow!("executor does not exist"))); } - None + rx.unwrap() } pub fn to_vec(&self) -> Vec> { diff --git a/crates/language/src/syntax_map.rs b/crates/language/src/syntax_map.rs index 5923241955e417d0b7d5ddf429647ac76b778305..88de8e690a6101bc461ef03d641db97da0a4d7c8 100644 --- a/crates/language/src/syntax_map.rs +++ b/crates/language/src/syntax_map.rs @@ -1,5 +1,6 @@ use crate::{Grammar, InjectionConfig, Language, LanguageRegistry}; use collections::HashMap; +use futures::FutureExt; use lazy_static::lazy_static; use parking_lot::Mutex; use std::{ @@ -382,11 +383,11 @@ impl SyntaxSnapshot { cursor.next(text); while let Some(layer) = cursor.item() { let SyntaxLayerContent::Pending { language_name } = &layer.content else { unreachable!() }; - if { - let language_registry = ®istry; - language_registry.language_for_name_or_extension(language_name) - } - .is_some() + if registry + .language_for_name_or_extension(language_name) + .now_or_never() + .and_then(|language| language.ok()) + .is_some() { resolved_injection_ranges.push(layer.range.to_offset(text)); } @@ -1116,7 +1117,10 @@ fn get_injections( combined_injection_ranges.clear(); for pattern in &config.patterns { if let (Some(language_name), true) = (pattern.language.as_ref(), pattern.combined) { - if let Some(language) = language_registry.language_for_name_or_extension(language_name) + if let Some(language) = language_registry + .language_for_name_or_extension(language_name) + .now_or_never() + .and_then(|language| language.ok()) { combined_injection_ranges.insert(language, Vec::new()); } @@ -1162,10 +1166,10 @@ fn get_injections( }; if let Some(language_name) = language_name { - let language = { - let language_name: &str = &language_name; - language_registry.language_for_name_or_extension(language_name) - }; + let language = language_registry + .language_for_name_or_extension(&language_name) + .now_or_never() + .and_then(|language| language.ok()); let range = text.anchor_before(step_range.start)..text.anchor_after(step_range.end); if let Some(language) = language { if combined { @@ -2522,7 +2526,11 @@ mod tests { registry.add(Arc::new(html_lang())); registry.add(Arc::new(erb_lang())); registry.add(Arc::new(markdown_lang())); - let language = registry.language_for_name(language_name).unwrap(); + let language = registry + .language_for_name(language_name) + .now_or_never() + .unwrap() + .unwrap(); let mut buffer = Buffer::new(0, 0, Default::default()); let mut mutated_syntax_map = SyntaxMap::new(); diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index a970c7bb19296ea6dacb0480daf73e57680bea86..003e4dd899afedafcd0eb780816b67c5108b9510 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -1838,7 +1838,11 @@ impl Project { ) -> Option<()> { // If the buffer has a language, set it and start the language server if we haven't already. let full_path = buffer.read(cx).file()?.full_path(cx); - let new_language = self.languages.language_for_path(&full_path)?; + let new_language = self + .languages + .language_for_path(&full_path) + .now_or_never()? + .ok()?; buffer.update(cx, |buffer, cx| { if buffer.language().map_or(true, |old_language| { !Arc::ptr_eq(old_language, &new_language) @@ -2248,8 +2252,14 @@ impl Project { }) .collect(); for (worktree_id, worktree_abs_path, full_path) in language_server_lookup_info { - let language = self.languages.language_for_path(&full_path)?; - self.restart_language_server(worktree_id, worktree_abs_path, language, cx); + if let Some(language) = self + .languages + .language_for_path(&full_path) + .now_or_never() + .and_then(|language| language.ok()) + { + self.restart_language_server(worktree_id, worktree_abs_path, language, cx); + } } None @@ -3278,12 +3288,14 @@ impl Project { path: path.into(), }; let signature = this.symbol_signature(&project_path); + let adapter_language = adapter_language.clone(); let language = this .languages .language_for_path(&project_path.path) - .unwrap_or(adapter_language.clone()); + .unwrap_or_else(move |_| adapter_language); let language_server_name = adapter.name.clone(); Some(async move { + let language = language.await; let label = language .label_for_symbol(&lsp_symbol.name, lsp_symbol.kind) .await; @@ -6060,7 +6072,7 @@ impl Project { worktree_id, path: PathBuf::from(serialized_symbol.path).into(), }; - let language = languages.language_for_path(&path.path); + let language = languages.language_for_path(&path.path).await.log_err(); Ok(Symbol { language_server_name: LanguageServerName( serialized_symbol.language_server_name.into(), diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index 2fbac3613ed3a6242c41db026e7b46b0d7f1aa50..79a6f67f621804b0f5d0193b62875c418c5c818d 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -167,9 +167,8 @@ pub fn init(app_state: &Arc, cx: &mut gpui::MutableAppContext) { }); cx.add_action({ let app_state = app_state.clone(); - move |workspace: &mut Workspace, _: &OpenLicenses, cx: &mut ViewContext| { + move |_: &mut Workspace, _: &OpenLicenses, cx: &mut ViewContext| { open_bundled_file( - workspace, app_state.clone(), "licenses.md", "Open Source License Attribution", @@ -192,9 +191,8 @@ pub fn init(app_state: &Arc, cx: &mut gpui::MutableAppContext) { }); cx.add_action({ let app_state = app_state.clone(); - move |workspace: &mut Workspace, _: &OpenDefaultKeymap, cx: &mut ViewContext| { + move |_: &mut Workspace, _: &OpenDefaultKeymap, cx: &mut ViewContext| { open_bundled_file( - workspace, app_state.clone(), "keymaps/default.json", "Default Key Bindings", @@ -205,11 +203,8 @@ pub fn init(app_state: &Arc, cx: &mut gpui::MutableAppContext) { }); cx.add_action({ let app_state = app_state.clone(); - move |workspace: &mut Workspace, - _: &OpenDefaultSettings, - cx: &mut ViewContext| { + move |_: &mut Workspace, _: &OpenDefaultSettings, cx: &mut ViewContext| { open_bundled_file( - workspace, app_state.clone(), "settings/default.json", "Default Settings", @@ -218,32 +213,41 @@ pub fn init(app_state: &Arc, cx: &mut gpui::MutableAppContext) { ); } }); - cx.add_action( - |workspace: &mut Workspace, _: &DebugElements, cx: &mut ViewContext| { + cx.add_action({ + let app_state = app_state.clone(); + move |_: &mut Workspace, _: &DebugElements, cx: &mut ViewContext| { + let app_state = app_state.clone(); + let markdown = app_state.languages.language_for_name("JSON"); let content = to_string_pretty(&cx.debug_elements()).unwrap(); - let project = workspace.project().clone(); - let json_language = project - .read(cx) - .languages() - .language_for_name("JSON") - .unwrap(); - if project.read(cx).is_remote() { - cx.propagate_action(); - } else if let Some(buffer) = project - .update(cx, |project, cx| { - project.create_buffer(&content, Some(json_language), cx) - }) - .log_err() - { - workspace.add_item( - Box::new( - cx.add_view(|cx| Editor::for_buffer(buffer, Some(project.clone()), cx)), - ), - cx, - ); - } - }, - ); + cx.spawn(|workspace, mut cx| async move { + let markdown = markdown.await.log_err(); + workspace + .update(&mut cx, |workspace, cx| { + workspace.with_local_workspace(&app_state, cx, move |workspace, cx| { + let project = workspace.project().clone(); + + let buffer = project + .update(cx, |project, cx| { + project.create_buffer(&content, markdown, cx) + }) + .expect("creating buffers on a local workspace always succeeds"); + let buffer = cx.add_model(|cx| { + MultiBuffer::singleton(buffer, cx) + .with_title("Debug Elements".into()) + }); + workspace.add_item( + Box::new(cx.add_view(|cx| { + Editor::for_multibuffer(buffer, Some(project.clone()), cx) + })), + cx, + ); + }) + }) + .await; + }) + .detach(); + } + }); cx.add_action( |workspace: &mut Workspace, _: &project_panel::ToggleFocus, @@ -628,6 +632,7 @@ fn open_telemetry_log_file( start_offset += newline_offset + 1; } let log_suffix = &log[start_offset..]; + let json = app_state.languages.language_for_name("JSON").await.log_err(); workspace.update(&mut cx, |workspace, cx| { let project = workspace.project().clone(); @@ -635,7 +640,7 @@ fn open_telemetry_log_file( .update(cx, |project, cx| project.create_buffer("", None, cx)) .expect("creating buffers on a local workspace always succeeds"); buffer.update(cx, |buffer, cx| { - buffer.set_language(app_state.languages.language_for_name("JSON"), cx); + buffer.set_language(json, cx); buffer.edit( [( 0..0, @@ -668,35 +673,42 @@ fn open_telemetry_log_file( } fn open_bundled_file( - workspace: &mut Workspace, app_state: Arc, asset_path: &'static str, title: &'static str, language: &'static str, cx: &mut ViewContext, ) { - workspace - .with_local_workspace(&app_state, cx, |workspace, cx| { - let project = workspace.project().clone(); - let buffer = project.update(cx, |project, cx| { - let text = Assets::get(asset_path) - .map(|f| f.data) - .unwrap_or_else(|| Cow::Borrowed(b"File not found")); - let text = str::from_utf8(text.as_ref()).unwrap(); - project - .create_buffer(text, project.languages().language_for_name(language), cx) - .expect("creating buffers on a local workspace always succeeds") - }); - let buffer = - cx.add_model(|cx| MultiBuffer::singleton(buffer, cx).with_title(title.into())); - workspace.add_item( - Box::new( - cx.add_view(|cx| Editor::for_multibuffer(buffer, Some(project.clone()), cx)), - ), - cx, - ); - }) - .detach(); + let language = app_state.languages.language_for_name(language); + cx.spawn(|workspace, mut cx| async move { + let language = language.await.log_err(); + workspace + .update(&mut cx, |workspace, cx| { + workspace.with_local_workspace(&app_state, cx, |workspace, cx| { + let project = workspace.project(); + let buffer = project.update(cx, |project, cx| { + let text = Assets::get(asset_path) + .map(|f| f.data) + .unwrap_or_else(|| Cow::Borrowed(b"File not found")); + let text = str::from_utf8(text.as_ref()).unwrap(); + project + .create_buffer(text, language, cx) + .expect("creating buffers on a local workspace always succeeds") + }); + let buffer = cx.add_model(|cx| { + MultiBuffer::singleton(buffer, cx).with_title(title.into()) + }); + workspace.add_item( + Box::new(cx.add_view(|cx| { + Editor::for_multibuffer(buffer, Some(project.clone()), cx) + })), + cx, + ); + }) + }) + .await; + }) + .detach(); } fn schema_file_match(path: &Path) -> &Path { From b402f27d5042308548e05de6f8626a1e285f01e1 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 24 Feb 2023 15:57:32 +0100 Subject: [PATCH 73/93] Introduce a new language picker that displays available languages Right now this panics when trying to select a language, so that's what we're going to implement next. Co-Authored-By: Julia Risley --- Cargo.lock | 16 ++ Cargo.toml | 1 + crates/language_selector/Cargo.toml | 20 ++ .../src/language_selector.rs | 196 ++++++++++++++++++ crates/zed/Cargo.toml | 1 + crates/zed/src/main.rs | 1 + 6 files changed, 235 insertions(+) create mode 100644 crates/language_selector/Cargo.toml create mode 100644 crates/language_selector/src/language_selector.rs diff --git a/Cargo.lock b/Cargo.lock index 87e32ed97de3e024cb144ecaa5bec866857970d3..94e7af6766ea1fc397343eb4ad7bcab4953c2915 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3286,6 +3286,21 @@ dependencies = [ "util", ] +[[package]] +name = "language_selector" +version = "0.1.0" +dependencies = [ + "editor", + "fuzzy", + "gpui", + "language", + "picker", + "project", + "settings", + "theme", + "workspace", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -8399,6 +8414,7 @@ dependencies = [ "isahc", "journal", "language", + "language_selector", "lazy_static", "libc", "log", diff --git a/Cargo.toml b/Cargo.toml index c74a76cccefe6c6de610b30c264a81e74b2654df..63882573ab1e32cddee4b3d4efd6d7ede7032240 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,6 +28,7 @@ members = [ "crates/gpui_macros", "crates/journal", "crates/language", + "crates/language_selector", "crates/live_kit_client", "crates/live_kit_server", "crates/lsp", diff --git a/crates/language_selector/Cargo.toml b/crates/language_selector/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..60ed0e6633640c6ba5c4ff80e400203f450e2321 --- /dev/null +++ b/crates/language_selector/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "language_selector" +version = "0.1.0" +edition = "2021" +publish = false + +[lib] +path = "src/language_selector.rs" +doctest = false + +[dependencies] +editor = { path = "../editor" } +fuzzy = { path = "../fuzzy" } +language = { path = "../language" } +gpui = { path = "../gpui" } +picker = { path = "../picker" } +project = { path = "../project" } +theme = { path = "../theme" } +settings = { path = "../settings" } +workspace = { path = "../workspace" } diff --git a/crates/language_selector/src/language_selector.rs b/crates/language_selector/src/language_selector.rs new file mode 100644 index 0000000000000000000000000000000000000000..d48a50ce932abec0c6f3f9d98a8edbd450a28648 --- /dev/null +++ b/crates/language_selector/src/language_selector.rs @@ -0,0 +1,196 @@ +use std::sync::Arc; + +use fuzzy::{match_strings, StringMatch, StringMatchCandidate}; +use gpui::{ + actions, elements::*, AnyViewHandle, AppContext, Entity, MouseState, MutableAppContext, + RenderContext, View, ViewContext, ViewHandle, +}; +use language::LanguageRegistry; +use picker::{Picker, PickerDelegate}; +use settings::Settings; +use workspace::{AppState, Workspace}; + +actions!(language_selector, [Toggle]); + +pub fn init(app_state: Arc, cx: &mut MutableAppContext) { + Picker::::init(cx); + cx.add_action({ + let language_registry = app_state.languages.clone(); + move |workspace, _: &Toggle, cx| { + LanguageSelector::toggle(workspace, language_registry.clone(), cx) + } + }); +} + +pub enum Event { + Dismissed, +} + +pub struct LanguageSelector { + language_registry: Arc, + matches: Vec, + picker: ViewHandle>, + selected_index: usize, +} + +impl LanguageSelector { + fn new(language_registry: Arc, cx: &mut ViewContext) -> Self { + let handle = cx.weak_handle(); + let picker = cx.add_view(|cx| Picker::new("Select Language...", handle, cx)); + + let mut matches = language_registry + .language_names() + .into_iter() + .enumerate() + .map(|(candidate_id, name)| StringMatch { + candidate_id, + score: 0.0, + positions: Default::default(), + string: name, + }) + .collect::>(); + matches.sort_unstable_by(|mat1, mat2| mat1.string.cmp(&mat2.string)); + + Self { + language_registry, + matches, + picker, + selected_index: 0, + } + } + + fn toggle( + workspace: &mut Workspace, + registry: Arc, + cx: &mut ViewContext, + ) { + workspace.toggle_modal(cx, |_, cx| { + let this = cx.add_view(|cx| Self::new(registry, cx)); + cx.subscribe(&this, Self::on_event).detach(); + this + }); + } + + fn on_event( + workspace: &mut Workspace, + _: ViewHandle, + event: &Event, + cx: &mut ViewContext, + ) { + match event { + Event::Dismissed => { + workspace.dismiss_modal(cx); + } + } + } +} + +impl Entity for LanguageSelector { + type Event = Event; +} + +impl View for LanguageSelector { + fn ui_name() -> &'static str { + "LanguageSelector" + } + + fn render(&mut self, cx: &mut RenderContext) -> ElementBox { + ChildView::new(self.picker.clone(), cx).boxed() + } + + fn focus_in(&mut self, _: AnyViewHandle, cx: &mut ViewContext) { + if cx.is_self_focused() { + cx.focus(&self.picker); + } + } +} + +impl PickerDelegate for LanguageSelector { + fn match_count(&self) -> usize { + self.matches.len() + } + + fn confirm(&mut self, cx: &mut ViewContext) { + todo!(); + cx.emit(Event::Dismissed); + } + + fn dismiss(&mut self, cx: &mut ViewContext) { + cx.emit(Event::Dismissed); + } + + fn selected_index(&self) -> usize { + self.selected_index + } + + fn set_selected_index(&mut self, ix: usize, cx: &mut ViewContext) { + self.selected_index = ix; + } + + fn update_matches(&mut self, query: String, cx: &mut ViewContext) -> gpui::Task<()> { + let background = cx.background().clone(); + let candidates = self + .language_registry + .language_names() + .into_iter() + .enumerate() + .map(|(id, name)| StringMatchCandidate { + id, + char_bag: name.as_str().into(), + string: name.clone(), + }) + .collect::>(); + + cx.spawn(|this, mut cx| async move { + let matches = if query.is_empty() { + candidates + .into_iter() + .enumerate() + .map(|(index, candidate)| StringMatch { + candidate_id: index, + string: candidate.string, + positions: Vec::new(), + score: 0.0, + }) + .collect() + } else { + match_strings( + &candidates, + &query, + false, + 100, + &Default::default(), + background, + ) + .await + }; + + this.update(&mut cx, |this, cx| { + this.matches = matches; + this.selected_index = this + .selected_index + .min(this.matches.len().saturating_sub(1)); + cx.notify(); + }); + }) + } + + fn render_match( + &self, + ix: usize, + mouse_state: &mut MouseState, + selected: bool, + cx: &AppContext, + ) -> ElementBox { + let settings = cx.global::(); + let theme = &settings.theme; + let theme_match = &self.matches[ix]; + let style = theme.picker.item.style_for(mouse_state, selected); + + Label::new(theme_match.string.clone(), style.label.clone()) + .with_highlights(theme_match.positions.clone()) + .contained() + .with_style(style.container) + .boxed() + } +} diff --git a/crates/zed/Cargo.toml b/crates/zed/Cargo.toml index 8060c2af115b0aa28b68a36f1d78f30ddfbbadad..a7c4861e023578c07e2f4ee7c7fd164c3e7116b9 100644 --- a/crates/zed/Cargo.toml +++ b/crates/zed/Cargo.toml @@ -40,6 +40,7 @@ go_to_line = { path = "../go_to_line" } gpui = { path = "../gpui" } journal = { path = "../journal" } language = { path = "../language" } +language_selector = { path = "../language_selector" } lsp = { path = "../lsp" } outline = { path = "../outline" } plugin_runtime = { path = "../plugin_runtime" } diff --git a/crates/zed/src/main.rs b/crates/zed/src/main.rs index b9e3ed550beb434c7da92138308131f09f3c8ac2..655e3968cf615f54e8f3150a47bd697677ae0973 100644 --- a/crates/zed/src/main.rs +++ b/crates/zed/src/main.rs @@ -185,6 +185,7 @@ fn main() { workspace::init(app_state.clone(), cx); journal::init(app_state.clone(), cx); + language_selector::init(app_state.clone(), cx); theme_selector::init(app_state.clone(), cx); zed::init(&app_state, cx); collab_ui::init(app_state.clone(), cx); From 686f5439ad033d61d72dcbf22f14a19d3ad45057 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 24 Feb 2023 16:28:56 +0100 Subject: [PATCH 74/93] Set buffer language when confirming selection in language selector Co-Authored-By: Julia Risley --- Cargo.lock | 1 + crates/editor/src/editor.rs | 9 ++ crates/language_selector/Cargo.toml | 1 + .../src/language_selector.rs | 83 ++++++++++++------- crates/project/src/project.rs | 36 +++++--- 5 files changed, 89 insertions(+), 41 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 94e7af6766ea1fc397343eb4ad7bcab4953c2915..0f19d4455f957463f61e8db34ff9fdb135ed4f3b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3290,6 +3290,7 @@ dependencies = [ name = "language_selector" version = "0.1.0" dependencies = [ + "anyhow", "editor", "fuzzy", "gpui", diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 3e7a14d2aea29312bb6b6853f18957ca116eb5f6..7f60309f6ab39ad1839598fc612d465e2f5cf19d 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -1254,6 +1254,15 @@ impl Editor { self.buffer.read(cx).language_at(point, cx) } + pub fn active_excerpt( + &self, + cx: &AppContext, + ) -> Option<(ExcerptId, ModelHandle, Range)> { + self.buffer + .read(cx) + .excerpt_containing(self.selections.newest_anchor().head(), cx) + } + fn style(&self, cx: &AppContext) -> EditorStyle { build_style( cx.global::(), diff --git a/crates/language_selector/Cargo.toml b/crates/language_selector/Cargo.toml index 60ed0e6633640c6ba5c4ff80e400203f450e2321..14aa41a4651072cc95773d177ab771779b62849d 100644 --- a/crates/language_selector/Cargo.toml +++ b/crates/language_selector/Cargo.toml @@ -18,3 +18,4 @@ project = { path = "../project" } theme = { path = "../theme" } settings = { path = "../settings" } workspace = { path = "../workspace" } +anyhow = "1.0" diff --git a/crates/language_selector/src/language_selector.rs b/crates/language_selector/src/language_selector.rs index d48a50ce932abec0c6f3f9d98a8edbd450a28648..5a2918660e07297c9eac60bb2edc2fb924ddea78 100644 --- a/crates/language_selector/src/language_selector.rs +++ b/crates/language_selector/src/language_selector.rs @@ -1,12 +1,14 @@ use std::sync::Arc; +use editor::Editor; use fuzzy::{match_strings, StringMatch, StringMatchCandidate}; use gpui::{ - actions, elements::*, AnyViewHandle, AppContext, Entity, MouseState, MutableAppContext, - RenderContext, View, ViewContext, ViewHandle, + actions, elements::*, AnyViewHandle, AppContext, Entity, ModelHandle, MouseState, + MutableAppContext, RenderContext, View, ViewContext, ViewHandle, }; -use language::LanguageRegistry; +use language::{Buffer, LanguageRegistry}; use picker::{Picker, PickerDelegate}; +use project::Project; use settings::Settings; use workspace::{AppState, Workspace}; @@ -27,32 +29,47 @@ pub enum Event { } pub struct LanguageSelector { + buffer: ModelHandle, + project: ModelHandle, language_registry: Arc, + candidates: Vec, matches: Vec, picker: ViewHandle>, selected_index: usize, } impl LanguageSelector { - fn new(language_registry: Arc, cx: &mut ViewContext) -> Self { + fn new( + buffer: ModelHandle, + project: ModelHandle, + language_registry: Arc, + cx: &mut ViewContext, + ) -> Self { let handle = cx.weak_handle(); let picker = cx.add_view(|cx| Picker::new("Select Language...", handle, cx)); - let mut matches = language_registry + let candidates = language_registry .language_names() .into_iter() .enumerate() - .map(|(candidate_id, name)| StringMatch { - candidate_id, - score: 0.0, + .map(|(candidate_id, name)| StringMatchCandidate::new(candidate_id, name)) + .collect::>(); + let mut matches = candidates + .iter() + .map(|candidate| StringMatch { + candidate_id: candidate.id, + score: 0., positions: Default::default(), - string: name, + string: candidate.string.clone(), }) .collect::>(); matches.sort_unstable_by(|mat1, mat2| mat1.string.cmp(&mat2.string)); Self { + buffer, + project, language_registry, + candidates, matches, picker, selected_index: 0, @@ -64,11 +81,18 @@ impl LanguageSelector { registry: Arc, cx: &mut ViewContext, ) { - workspace.toggle_modal(cx, |_, cx| { - let this = cx.add_view(|cx| Self::new(registry, cx)); - cx.subscribe(&this, Self::on_event).detach(); - this - }); + if let Some((_, buffer, _)) = workspace + .active_item(cx) + .and_then(|active_item| active_item.act_as::(cx)) + .and_then(|editor| editor.read(cx).active_excerpt(cx)) + { + workspace.toggle_modal(cx, |workspace, cx| { + let project = workspace.project().clone(); + let this = cx.add_view(|cx| Self::new(buffer, project, registry, cx)); + cx.subscribe(&this, Self::on_event).detach(); + this + }); + } } fn on_event( @@ -111,7 +135,21 @@ impl PickerDelegate for LanguageSelector { } fn confirm(&mut self, cx: &mut ViewContext) { - todo!(); + if let Some(mat) = self.matches.get(self.selected_index) { + let language_name = &self.candidates[mat.candidate_id].string; + let language = self.language_registry.language_for_name(language_name); + cx.spawn(|this, mut cx| async move { + let language = language.await?; + this.update(&mut cx, |this, cx| { + this.project.update(cx, |project, cx| { + project.set_language_for_buffer(&this.buffer, language, cx); + }); + }); + anyhow::Ok(()) + }) + .detach_and_log_err(cx); + } + cx.emit(Event::Dismissed); } @@ -123,24 +161,13 @@ impl PickerDelegate for LanguageSelector { self.selected_index } - fn set_selected_index(&mut self, ix: usize, cx: &mut ViewContext) { + fn set_selected_index(&mut self, ix: usize, _: &mut ViewContext) { self.selected_index = ix; } fn update_matches(&mut self, query: String, cx: &mut ViewContext) -> gpui::Task<()> { let background = cx.background().clone(); - let candidates = self - .language_registry - .language_names() - .into_iter() - .enumerate() - .map(|(id, name)| StringMatchCandidate { - id, - char_bag: name.as_str().into(), - string: name.clone(), - }) - .collect::>(); - + let candidates = self.candidates.clone(); cx.spawn(|this, mut cx| async move { let matches = if query.is_empty() { candidates diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index 003e4dd899afedafcd0eb780816b67c5108b9510..a164b5b885f927737efba79a5693ff22aa1500aa 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -1464,7 +1464,7 @@ impl Project { }) .await?; this.update(&mut cx, |this, cx| { - this.assign_language_to_buffer(&buffer, cx); + this.detect_language_for_buffer(&buffer, cx); this.register_buffer_with_language_server(&buffer, cx); }); Ok(()) @@ -1531,7 +1531,7 @@ impl Project { }) .detach(); - self.assign_language_to_buffer(buffer, cx); + self.detect_language_for_buffer(buffer, cx); self.register_buffer_with_language_server(buffer, cx); cx.observe_release(buffer, |this, buffer, cx| { if let Some(file) = File::from_dyn(buffer.file()) { @@ -1818,7 +1818,7 @@ impl Project { } for buffer in plain_text_buffers { - project.assign_language_to_buffer(&buffer, cx); + project.detect_language_for_buffer(&buffer, cx); project.register_buffer_with_language_server(&buffer, cx); } @@ -1831,7 +1831,7 @@ impl Project { }) } - fn assign_language_to_buffer( + fn detect_language_for_buffer( &mut self, buffer: &ModelHandle, cx: &mut ModelContext, @@ -1843,6 +1843,16 @@ impl Project { .language_for_path(&full_path) .now_or_never()? .ok()?; + self.set_language_for_buffer(buffer, new_language, cx); + None + } + + pub fn set_language_for_buffer( + &mut self, + buffer: &ModelHandle, + new_language: Arc, + cx: &mut ModelContext, + ) { buffer.update(cx, |buffer, cx| { if buffer.language().map_or(true, |old_language| { !Arc::ptr_eq(old_language, &new_language) @@ -1851,13 +1861,13 @@ impl Project { } }); - let file = File::from_dyn(buffer.read(cx).file())?; - let worktree = file.worktree.read(cx).as_local()?; - let worktree_id = worktree.id(); - let worktree_abs_path = worktree.abs_path().clone(); - self.start_language_server(worktree_id, worktree_abs_path, new_language, cx); - - None + if let Some(file) = File::from_dyn(buffer.read(cx).file()) { + if let Some(worktree) = file.worktree.read(cx).as_local() { + let worktree_id = worktree.id(); + let worktree_abs_path = worktree.abs_path().clone(); + self.start_language_server(worktree_id, worktree_abs_path, new_language, cx); + } + } } fn merge_json_value_into(source: serde_json::Value, target: &mut serde_json::Value) { @@ -4553,7 +4563,7 @@ impl Project { for (buffer, old_path) in renamed_buffers { self.unregister_buffer_from_language_server(&buffer, old_path, cx); - self.assign_language_to_buffer(&buffer, cx); + self.detect_language_for_buffer(&buffer, cx); self.register_buffer_with_language_server(&buffer, cx); } } @@ -5222,7 +5232,7 @@ impl Project { buffer.update(cx, |buffer, cx| { buffer.file_updated(Arc::new(file), cx).detach(); }); - this.assign_language_to_buffer(&buffer, cx); + this.detect_language_for_buffer(&buffer, cx); } Ok(()) }) From f28806d09ba0f79e27c4c32c10b1cc844b157c98 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 10 Mar 2023 15:48:39 +0100 Subject: [PATCH 75/93] Emphasize currently-selected language --- crates/language_selector/src/language_selector.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/crates/language_selector/src/language_selector.rs b/crates/language_selector/src/language_selector.rs index 5a2918660e07297c9eac60bb2edc2fb924ddea78..786dd5abe0ba92a6425cc94e197bc4fc56bb2762 100644 --- a/crates/language_selector/src/language_selector.rs +++ b/crates/language_selector/src/language_selector.rs @@ -211,11 +211,16 @@ impl PickerDelegate for LanguageSelector { ) -> ElementBox { let settings = cx.global::(); let theme = &settings.theme; - let theme_match = &self.matches[ix]; + let mat = &self.matches[ix]; let style = theme.picker.item.style_for(mouse_state, selected); + let buffer_language_name = self.buffer.read(cx).language().map(|l| l.name()); + let mut label = mat.string.clone(); + if buffer_language_name.as_deref() == Some(mat.string.as_str()) { + label.push_str(" (current)"); + } - Label::new(theme_match.string.clone(), style.label.clone()) - .with_highlights(theme_match.positions.clone()) + Label::new(label, style.label.clone()) + .with_highlights(mat.positions.clone()) .contained() .with_style(style.container) .boxed() From ce828d55d5669eae01781aafa5d3a65cbd52d313 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 10 Mar 2023 16:32:18 +0100 Subject: [PATCH 76/93] Bind `language_selector::Toggle` to `cmd-k m` Co-Authored-By: Nathan Sobo --- assets/keymaps/default.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/assets/keymaps/default.json b/assets/keymaps/default.json index cce65eda8abcadcb632d1b496c10b2dc283dc548..57f5075aca9a6678bb6a7231d8fdd5a3036c5aef 100644 --- a/assets/keymaps/default.json +++ b/assets/keymaps/default.json @@ -353,7 +353,8 @@ "cmd-shift-p": "command_palette::Toggle", "cmd-shift-m": "diagnostics::Deploy", "cmd-shift-e": "project_panel::ToggleFocus", - "cmd-alt-s": "workspace::SaveAll" + "cmd-alt-s": "workspace::SaveAll", + "cmd-k m": "language_selector::Toggle" } }, // Bindings from Sublime Text @@ -537,4 +538,4 @@ ] } } -] \ No newline at end of file +] From 6e37ff880f616f7128c09e567af22c4ee46c3cd7 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 10 Mar 2023 17:02:52 +0100 Subject: [PATCH 77/93] Replace "Give Feedback" with an icon and move it to the left This is so we can show the current language in the status bar on the right, and having two pieces of text sitting next to each other felt too busy. Co-Authored-By: Nathan Sobo --- assets/icons/speech_bubble_12.svg | 3 +++ crates/feedback/src/deploy_feedback_button.rs | 20 ++++++++++++------- crates/theme/src/theme.rs | 2 +- crates/zed/src/zed.rs | 2 +- styles/src/styleTree/statusBar.ts | 8 ++++++-- 5 files changed, 24 insertions(+), 11 deletions(-) create mode 100644 assets/icons/speech_bubble_12.svg diff --git a/assets/icons/speech_bubble_12.svg b/assets/icons/speech_bubble_12.svg new file mode 100644 index 0000000000000000000000000000000000000000..f5f330056a34f1261d31416b688bcc86dcdf8bf1 --- /dev/null +++ b/assets/icons/speech_bubble_12.svg @@ -0,0 +1,3 @@ + + + diff --git a/crates/feedback/src/deploy_feedback_button.rs b/crates/feedback/src/deploy_feedback_button.rs index 8fcafdfedee101458f0513d145d504831bfbdb34..7519d2d06e649164cdd742dca4d3dc92e51d7899 100644 --- a/crates/feedback/src/deploy_feedback_button.rs +++ b/crates/feedback/src/deploy_feedback_button.rs @@ -1,7 +1,4 @@ -use gpui::{ - elements::{MouseEventHandler, ParentElement, Stack, Text}, - CursorStyle, Element, ElementBox, Entity, MouseButton, RenderContext, View, ViewContext, -}; +use gpui::{elements::*, CursorStyle, Entity, MouseButton, RenderContext, View, ViewContext}; use settings::Settings; use workspace::{item::ItemHandle, StatusItemView}; @@ -23,9 +20,18 @@ impl View for DeployFeedbackButton { .with_child( MouseEventHandler::::new(0, cx, |state, cx| { let theme = &cx.global::().theme; - let theme = &theme.workspace.status_bar.feedback; - - Text::new("Give Feedback", theme.style_for(state, true).clone()).boxed() + let style = &theme.workspace.status_bar.feedback.style_for(state, false); + Svg::new("icons/speech_bubble_12.svg") + .with_color(style.color) + .constrained() + .with_width(style.icon_width) + .aligned() + .constrained() + .with_width(style.button_width) + .with_height(style.button_width) + .contained() + .with_style(style.container) + .boxed() }) .with_cursor_style(CursorStyle::PointingHand) .on_click(MouseButton::Left, |_, cx| cx.dispatch_action(GiveFeedback)) diff --git a/crates/theme/src/theme.rs b/crates/theme/src/theme.rs index 484c542edeffce8b22c8f2f29ae4f672c0693399..56ef87e0af3e3ca6b955d75e9adf843ef6cff833 100644 --- a/crates/theme/src/theme.rs +++ b/crates/theme/src/theme.rs @@ -280,7 +280,7 @@ pub struct StatusBar { pub auto_update_progress_message: TextStyle, pub auto_update_done_message: TextStyle, pub lsp_status: Interactive, - pub feedback: Interactive, + pub feedback: Interactive, pub sidebar_buttons: StatusBarSidebarButtons, pub diagnostic_summary: Interactive, pub diagnostic_message: Interactive, diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index 79a6f67f621804b0f5d0193b62875c418c5c818d..f853e41c0429cddc1cb1c5fcee14dff429cfb3a9 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -342,10 +342,10 @@ pub fn initialize_workspace( let feedback_button = cx.add_view(|_| feedback::deploy_feedback_button::DeployFeedbackButton {}); workspace.status_bar().update(cx, |status_bar, cx| { + status_bar.add_left_item(feedback_button, cx); status_bar.add_left_item(diagnostic_summary, cx); status_bar.add_left_item(activity_indicator, cx); status_bar.add_right_item(cursor_position, cx); - status_bar.add_right_item(feedback_button, cx); }); auto_update::notify_of_any_new_update(cx.weak_handle(), cx); diff --git a/styles/src/styleTree/statusBar.ts b/styles/src/styleTree/statusBar.ts index a60a55df1ecaae3ce52edfc82c90222db30718cb..eb72346788a78b62be63600587eefc981676dc7d 100644 --- a/styles/src/styleTree/statusBar.ts +++ b/styles/src/styleTree/statusBar.ts @@ -45,8 +45,12 @@ export default function statusBar(colorScheme: ColorScheme) { hover: text(layer, "sans", "hovered"), }, feedback: { - ...text(layer, "sans", "variant"), - hover: text(layer, "sans", "hovered"), + color: foreground(layer, "variant"), + iconWidth: 14, + buttonWidth: 20, + hover: { + color: foreground(layer, "on"), + }, }, diagnosticSummary: { height: 20, From b3c7526fb5609e06cb3dad5771adf4de0389a929 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 10 Mar 2023 17:21:06 +0100 Subject: [PATCH 78/93] Return last excerpt in MultiBuffer::excerpt_containing if overshooting --- crates/editor/src/multi_buffer.rs | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/crates/editor/src/multi_buffer.rs b/crates/editor/src/multi_buffer.rs index da3c6bc4bd44ad76a01c407f41be7e6429a1bbd1..e1e82859317929404182b7766d34b143ff5c01dc 100644 --- a/crates/editor/src/multi_buffer.rs +++ b/crates/editor/src/multi_buffer.rs @@ -1082,18 +1082,21 @@ impl MultiBuffer { let mut cursor = snapshot.excerpts.cursor::(); cursor.seek(&position, Bias::Right, &()); - cursor.item().map(|excerpt| { - ( - excerpt.id.clone(), - self.buffers - .borrow() - .get(&excerpt.buffer_id) - .unwrap() - .buffer - .clone(), - excerpt.range.context.clone(), - ) - }) + cursor + .item() + .or_else(|| snapshot.excerpts.last()) + .map(|excerpt| { + ( + excerpt.id.clone(), + self.buffers + .borrow() + .get(&excerpt.buffer_id) + .unwrap() + .buffer + .clone(), + excerpt.range.context.clone(), + ) + }) } // If point is at the end of the buffer, the last excerpt is returned From 693172854c45bbb910973fb2dde941a0b3308944 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 10 Mar 2023 17:28:27 +0100 Subject: [PATCH 79/93] Show active buffer's language on the right in the status bar --- .../src/active_buffer_language.rs | 86 +++++++++++++++++++ .../src/language_selector.rs | 4 +- crates/theme/src/theme.rs | 1 + crates/zed/src/zed.rs | 2 + styles/src/styleTree/statusBar.ts | 9 +- 5 files changed, 100 insertions(+), 2 deletions(-) create mode 100644 crates/language_selector/src/active_buffer_language.rs diff --git a/crates/language_selector/src/active_buffer_language.rs b/crates/language_selector/src/active_buffer_language.rs new file mode 100644 index 0000000000000000000000000000000000000000..c4129d1448c1eee0712a5d43765b3d08ea2e4b23 --- /dev/null +++ b/crates/language_selector/src/active_buffer_language.rs @@ -0,0 +1,86 @@ +use editor::Editor; +use gpui::{ + elements::*, CursorStyle, Entity, MouseButton, RenderContext, Subscription, View, ViewContext, + ViewHandle, +}; +use settings::Settings; +use std::sync::Arc; +use workspace::{item::ItemHandle, StatusItemView}; + +pub struct ActiveBufferLanguage { + active_language: Option>, + _observe_active_editor: Option, +} + +impl Default for ActiveBufferLanguage { + fn default() -> Self { + Self::new() + } +} + +impl ActiveBufferLanguage { + pub fn new() -> Self { + Self { + active_language: None, + _observe_active_editor: None, + } + } + + fn update_language(&mut self, editor: ViewHandle, cx: &mut ViewContext) { + let editor = editor.read(cx); + self.active_language.take(); + if let Some((_, buffer, _)) = editor.active_excerpt(cx) { + if let Some(language) = buffer.read(cx).language() { + self.active_language = Some(language.name()); + } + } + + cx.notify(); + } +} + +impl Entity for ActiveBufferLanguage { + type Event = (); +} + +impl View for ActiveBufferLanguage { + fn ui_name() -> &'static str { + "ActiveBufferLanguage" + } + + fn render(&mut self, cx: &mut RenderContext) -> ElementBox { + if let Some(active_language) = self.active_language.as_ref() { + MouseEventHandler::::new(0, cx, |state, cx| { + let theme = &cx.global::().theme.workspace.status_bar; + let style = theme.active_language.style_for(state, false); + Label::new(active_language.to_string(), style.text.clone()) + .contained() + .with_style(style.container) + .boxed() + }) + .with_cursor_style(CursorStyle::PointingHand) + .on_click(MouseButton::Left, |_, cx| cx.dispatch_action(crate::Toggle)) + .boxed() + } else { + Empty::new().boxed() + } + } +} + +impl StatusItemView for ActiveBufferLanguage { + fn set_active_pane_item( + &mut self, + active_pane_item: Option<&dyn ItemHandle>, + cx: &mut ViewContext, + ) { + if let Some(editor) = active_pane_item.and_then(|item| item.act_as::(cx)) { + self._observe_active_editor = Some(cx.observe(&editor, Self::update_language)); + self.update_language(editor, cx); + } else { + self.active_language = None; + self._observe_active_editor = None; + } + + cx.notify(); + } +} diff --git a/crates/language_selector/src/language_selector.rs b/crates/language_selector/src/language_selector.rs index 786dd5abe0ba92a6425cc94e197bc4fc56bb2762..711e36f9c442ca1eaf297f7a14ed66a6cd0060bc 100644 --- a/crates/language_selector/src/language_selector.rs +++ b/crates/language_selector/src/language_selector.rs @@ -1,5 +1,6 @@ -use std::sync::Arc; +mod active_buffer_language; +pub use active_buffer_language::ActiveBufferLanguage; use editor::Editor; use fuzzy::{match_strings, StringMatch, StringMatchCandidate}; use gpui::{ @@ -10,6 +11,7 @@ use language::{Buffer, LanguageRegistry}; use picker::{Picker, PickerDelegate}; use project::Project; use settings::Settings; +use std::sync::Arc; use workspace::{AppState, Workspace}; actions!(language_selector, [Toggle]); diff --git a/crates/theme/src/theme.rs b/crates/theme/src/theme.rs index 56ef87e0af3e3ca6b955d75e9adf843ef6cff833..aa379bf838818121ece93ccbc639746d8b9aaa64 100644 --- a/crates/theme/src/theme.rs +++ b/crates/theme/src/theme.rs @@ -277,6 +277,7 @@ pub struct StatusBar { pub height: f32, pub item_spacing: f32, pub cursor_position: TextStyle, + pub active_language: Interactive, pub auto_update_progress_message: TextStyle, pub auto_update_done_message: TextStyle, pub lsp_status: Interactive, diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index f853e41c0429cddc1cb1c5fcee14dff429cfb3a9..664833de1e257a948a11b3f4b48578f6d42610ab 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -338,6 +338,7 @@ pub fn initialize_workspace( cx.add_view(|cx| diagnostics::items::DiagnosticIndicator::new(workspace.project(), cx)); let activity_indicator = activity_indicator::ActivityIndicator::new(workspace, app_state.languages.clone(), cx); + let active_buffer_language = cx.add_view(|_| language_selector::ActiveBufferLanguage::new()); let cursor_position = cx.add_view(|_| editor::items::CursorPosition::new()); let feedback_button = cx.add_view(|_| feedback::deploy_feedback_button::DeployFeedbackButton {}); @@ -346,6 +347,7 @@ pub fn initialize_workspace( status_bar.add_left_item(diagnostic_summary, cx); status_bar.add_left_item(activity_indicator, cx); status_bar.add_right_item(cursor_position, cx); + status_bar.add_right_item(active_buffer_language, cx); }); auto_update::notify_of_any_new_update(cx.weak_handle(), cx); diff --git a/styles/src/styleTree/statusBar.ts b/styles/src/styleTree/statusBar.ts index eb72346788a78b62be63600587eefc981676dc7d..de33f3d1d5361286557b5e7c8415782f8d36784f 100644 --- a/styles/src/styleTree/statusBar.ts +++ b/styles/src/styleTree/statusBar.ts @@ -25,6 +25,12 @@ export default function statusBar(colorScheme: ColorScheme) { }, border: border(layer, { top: true, overlay: true }), cursorPosition: text(layer, "sans", "variant"), + activeLanguage: { + ...text(layer, "sans", "variant"), + hover: { + ...text(layer, "sans", "on") + } + }, autoUpdateProgressMessage: text(layer, "sans", "variant"), autoUpdateDoneMessage: text(layer, "sans", "variant"), lspStatus: { @@ -45,9 +51,10 @@ export default function statusBar(colorScheme: ColorScheme) { hover: text(layer, "sans", "hovered"), }, feedback: { + margin: { left: 2 }, color: foreground(layer, "variant"), iconWidth: 14, - buttonWidth: 20, + buttonWidth: 14, hover: { color: foreground(layer, "on"), }, From f50b51bdad4333f94a65a6e3eea45026a9b246d9 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 10 Mar 2023 17:37:45 +0100 Subject: [PATCH 80/93] Adjust styling --- crates/theme/src/theme.rs | 2 +- crates/zed/src/zed.rs | 2 +- styles/src/styleTree/statusBar.ts | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/crates/theme/src/theme.rs b/crates/theme/src/theme.rs index aa379bf838818121ece93ccbc639746d8b9aaa64..87504d6cd98423424d6994e7f06d6ef1f2e666ed 100644 --- a/crates/theme/src/theme.rs +++ b/crates/theme/src/theme.rs @@ -277,7 +277,7 @@ pub struct StatusBar { pub height: f32, pub item_spacing: f32, pub cursor_position: TextStyle, - pub active_language: Interactive, + pub active_language: Interactive, pub auto_update_progress_message: TextStyle, pub auto_update_done_message: TextStyle, pub lsp_status: Interactive, diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index 664833de1e257a948a11b3f4b48578f6d42610ab..26989102e4221dcca3fdcef447271d4b232a7feb 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -346,8 +346,8 @@ pub fn initialize_workspace( status_bar.add_left_item(feedback_button, cx); status_bar.add_left_item(diagnostic_summary, cx); status_bar.add_left_item(activity_indicator, cx); - status_bar.add_right_item(cursor_position, cx); status_bar.add_right_item(active_buffer_language, cx); + status_bar.add_right_item(cursor_position, cx); }); auto_update::notify_of_any_new_update(cx.weak_handle(), cx); diff --git a/styles/src/styleTree/statusBar.ts b/styles/src/styleTree/statusBar.ts index de33f3d1d5361286557b5e7c8415782f8d36784f..e5c07c07c2b1598a04e31ec34b20fd7a16afc9fe 100644 --- a/styles/src/styleTree/statusBar.ts +++ b/styles/src/styleTree/statusBar.ts @@ -26,6 +26,7 @@ export default function statusBar(colorScheme: ColorScheme) { border: border(layer, { top: true, overlay: true }), cursorPosition: text(layer, "sans", "variant"), activeLanguage: { + padding: { left: 6, right: 6 }, ...text(layer, "sans", "variant"), hover: { ...text(layer, "sans", "on") From bb721a08f56e87391280937686e1be2ce3a95ef4 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 10 Mar 2023 17:43:48 +0100 Subject: [PATCH 81/93] :lipstick: --- crates/language_selector/src/active_buffer_language.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/language_selector/src/active_buffer_language.rs b/crates/language_selector/src/active_buffer_language.rs index c4129d1448c1eee0712a5d43765b3d08ea2e4b23..1da0b4323c5134da7a0336f6816509ccbf0ba7d3 100644 --- a/crates/language_selector/src/active_buffer_language.rs +++ b/crates/language_selector/src/active_buffer_language.rs @@ -27,8 +27,9 @@ impl ActiveBufferLanguage { } fn update_language(&mut self, editor: ViewHandle, cx: &mut ViewContext) { - let editor = editor.read(cx); self.active_language.take(); + + let editor = editor.read(cx); if let Some((_, buffer, _)) = editor.active_excerpt(cx) { if let Some(language) = buffer.read(cx).language() { self.active_language = Some(language.name()); From 281ff92236cfa2fc73e793f9ae4666700ec5c5d7 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Fri, 10 Mar 2023 09:54:20 -0800 Subject: [PATCH 82/93] Stub out blank pane experience --- assets/icons/logo_256.svg | 41 ------------------ assets/icons/logo_shadow_256.svg | 23 ---------- crates/workspace/src/pane.rs | 73 ++++---------------------------- 3 files changed, 8 insertions(+), 129 deletions(-) delete mode 100644 assets/icons/logo_256.svg delete mode 100644 assets/icons/logo_shadow_256.svg diff --git a/assets/icons/logo_256.svg b/assets/icons/logo_256.svg deleted file mode 100644 index 4629600b4104cdbd18e545b967fa416d007c6675..0000000000000000000000000000000000000000 --- a/assets/icons/logo_256.svg +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/assets/icons/logo_shadow_256.svg b/assets/icons/logo_shadow_256.svg deleted file mode 100644 index 6c331f43ab3f4f2c57b4569c212f5e423d8726d1..0000000000000000000000000000000000000000 --- a/assets/icons/logo_shadow_256.svg +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - diff --git a/crates/workspace/src/pane.rs b/crates/workspace/src/pane.rs index 6d20700bcc81aff330c6c61303f49a528009e5da..587f180a4aaa73722869f235faa713e98f593275 100644 --- a/crates/workspace/src/pane.rs +++ b/crates/workspace/src/pane.rs @@ -217,8 +217,8 @@ pub struct Pane { toolbar: ViewHandle, tab_bar_context_menu: ViewHandle, docked: Option, - background_actions: BackgroundActions, - workspace_id: usize, + _background_actions: BackgroundActions, + _workspace_id: usize, } pub struct ItemNavHistory { @@ -301,8 +301,8 @@ impl Pane { toolbar: cx.add_view(|_| Toolbar::new(handle)), tab_bar_context_menu: context_menu, docked, - background_actions, - workspace_id, + _background_actions: background_actions, + _workspace_id: workspace_id, } } @@ -1427,68 +1427,11 @@ impl Pane { .boxed() } - fn render_blank_pane(&mut self, theme: &Theme, cx: &mut RenderContext) -> ElementBox { + fn render_blank_pane(&mut self, theme: &Theme, _cx: &mut RenderContext) -> ElementBox { let background = theme.workspace.background; - let theme = &theme.workspace.blank_pane; - Stack::new() - .with_children([ - Empty::new() - .contained() - .with_background_color(background) - .boxed(), - Flex::column() - .align_children_center() - .with_children([ - Stack::new() - .with_children([ - theme::ui::icon(&theme.logo_shadow).aligned().boxed(), - theme::ui::icon(&theme.logo).aligned().boxed(), - ]) - .contained() - .with_style(theme.logo_container) - .boxed(), - Flex::column() - .with_children({ - enum KeyboardHint {} - let keyboard_hint = &theme.keyboard_hint; - let workspace_id = self.workspace_id; - (self.background_actions)().into_iter().enumerate().map( - move |(idx, (text, action))| { - let hint_action = action.boxed_clone(); - MouseEventHandler::::new( - idx, - cx, - move |state, cx| { - let style = keyboard_hint.style_for(state, false); - theme::ui::keystroke_label_for( - cx.window_id(), - workspace_id, - text, - &style, - &style, - hint_action, - ) - .boxed() - }, - ) - .on_click(MouseButton::Left, move |_, cx| { - cx.dispatch_any_action(action.boxed_clone()) - }) - .with_cursor_style(CursorStyle::PointingHand) - .boxed() - }, - ) - }) - .contained() - .with_style(theme.keyboard_hints) - .constrained() - .with_max_width(theme.keyboard_hint_width) - .aligned() - .boxed(), - ]) - .aligned() - .boxed(), - ]) + Empty::new() + .contained() + .with_background_color(background) .boxed() } } From 00a38e4c3b1149ba11f0a5dbde0b1be78681f5db Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Fri, 10 Mar 2023 12:12:32 -0800 Subject: [PATCH 83/93] Bound the search range for the keybindings by the highest handler path --- crates/gpui/src/app.rs | 58 ++++++++++++++++++----- crates/gpui/src/keymap_matcher/binding.rs | 9 ---- 2 files changed, 46 insertions(+), 21 deletions(-) diff --git a/crates/gpui/src/app.rs b/crates/gpui/src/app.rs index ab88a39a9aac7e4a705bfc7f4df2c668d08b6f83..2f29815f0328b29331ecdbab2291189d0372299a 100644 --- a/crates/gpui/src/app.rs +++ b/crates/gpui/src/app.rs @@ -485,7 +485,9 @@ pub struct MutableAppContext { cx: AppContext, action_deserializers: HashMap<&'static str, (TypeId, DeserializeActionCallback)>, capture_actions: HashMap>>>, + // Entity Types -> { Action Types -> Action Handlers } actions: HashMap>>>, + // Action Types -> Action Handlers global_actions: HashMap>, keystroke_matcher: KeymapMatcher, next_entity_id: usize, @@ -1239,20 +1241,34 @@ impl MutableAppContext { action: &dyn Action, ) -> Option> { let mut contexts = Vec::new(); - for view_id in self.ancestors(window_id, view_id) { + let mut highest_handler = None; + for (i, view_id) in self.ancestors(window_id, view_id).enumerate() { if let Some(view) = self.views.get(&(window_id, view_id)) { + if let Some(actions) = self.actions.get(&view.as_any().type_id()) { + if actions.contains_key(&action.as_any().type_id()) { + highest_handler = Some(i); + } + } contexts.push(view.keymap_context(self)); } } + if self.global_actions.contains_key(&action.as_any().type_id()) { + highest_handler = Some(contexts.len()) + } + self.keystroke_matcher .bindings_for_action_type(action.as_any().type_id()) .find_map(|b| { - if b.match_dispatch_path_context(&contexts) { - Some(b.keystrokes().into()) - } else { - None - } + highest_handler + .map(|highest_handler| { + if (0..=highest_handler).any(|depth| b.match_context(&contexts[depth..])) { + Some(b.keystrokes().into()) + } else { + None + } + }) + .flatten() }) } @@ -1261,29 +1277,47 @@ impl MutableAppContext { window_id: usize, view_id: usize, ) -> impl Iterator, SmallVec<[&Binding; 1]>)> { - let mut action_types: HashSet<_> = self.global_actions.keys().copied().collect(); - let mut contexts = Vec::new(); - for view_id in self.ancestors(window_id, view_id) { + let mut handler_depth_by_action_type = HashMap::>::default(); + for (i, view_id) in self.ancestors(window_id, view_id).enumerate() { if let Some(view) = self.views.get(&(window_id, view_id)) { contexts.push(view.keymap_context(self)); let view_type = view.as_any().type_id(); if let Some(actions) = self.actions.get(&view_type) { - action_types.extend(actions.keys().copied()); + handler_depth_by_action_type.extend( + actions + .keys() + .copied() + .map(|action_type| (action_type, Some(i))), + ); } } } + handler_depth_by_action_type.extend( + self.global_actions + .keys() + .copied() + .map(|action_type| (action_type, None)), + ); + self.action_deserializers .iter() .filter_map(move |(name, (type_id, deserialize))| { - if action_types.contains(type_id) { + if let Some(action_depth) = handler_depth_by_action_type.get(type_id) { Some(( *name, deserialize("{}").ok()?, self.keystroke_matcher .bindings_for_action_type(*type_id) - .filter(|b| b.match_dispatch_path_context(&contexts)) + .filter(|b| { + if let Some(action_depth) = *action_depth { + (0..=action_depth) + .any(|depth| b.match_context(&contexts[depth..])) + } else { + true + } + }) .collect(), )) } else { diff --git a/crates/gpui/src/keymap_matcher/binding.rs b/crates/gpui/src/keymap_matcher/binding.rs index 1b0217b5ff141751a8b2a35ffa37e93774f67c93..c1cfd14e82d8d3e3235a7a2c3e7d507cd78d9648 100644 --- a/crates/gpui/src/keymap_matcher/binding.rs +++ b/crates/gpui/src/keymap_matcher/binding.rs @@ -42,15 +42,6 @@ impl Binding { .unwrap_or(true) } - pub fn match_dispatch_path_context(&self, contexts: &[KeymapContext]) -> bool { - for i in 0..contexts.len() { - if self.match_context(&contexts[i..]) { - return true; - } - } - false - } - pub fn match_keys_and_context( &self, pending_keystrokes: &Vec, From ddbffd2c41d01a7c79284fa86ba31d5785158d70 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Fri, 10 Mar 2023 12:23:29 -0800 Subject: [PATCH 84/93] Make terminal fallback correctly when unable to deserialize your cwd --- crates/terminal_view/src/terminal_view.rs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/crates/terminal_view/src/terminal_view.rs b/crates/terminal_view/src/terminal_view.rs index 110815e87027e7c018d3a25d6e7115c5b48b0be3..330be6dcf484d763cfb3453e4b6d9318fd29bd57 100644 --- a/crates/terminal_view/src/terminal_view.rs +++ b/crates/terminal_view/src/terminal_view.rs @@ -653,7 +653,7 @@ impl Item for TerminalView { fn deserialize( project: ModelHandle, - _workspace: WeakViewHandle, + workspace: WeakViewHandle, workspace_id: workspace::WorkspaceId, item_id: workspace::ItemId, cx: &mut ViewContext, @@ -663,7 +663,18 @@ impl Item for TerminalView { let cwd = TERMINAL_DB .get_working_directory(item_id, workspace_id) .log_err() - .flatten(); + .flatten() + .or_else(|| { + cx.read(|cx| { + let strategy = cx.global::().terminal_strategy(); + workspace + .upgrade(cx) + .map(|workspace| { + get_working_directory(workspace.read(cx), cx, strategy) + }) + .flatten() + }) + }); cx.update(|cx| { let terminal = project.update(cx, |project, cx| { From e45104a1c046cd2dd441f0363cd25be933763627 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Fri, 10 Mar 2023 12:48:11 -0800 Subject: [PATCH 85/93] Move feedback to overflow menu and help menu --- Cargo.lock | 1 + crates/collab_ui/Cargo.toml | 1 + crates/collab_ui/src/collab_titlebar_item.rs | 18 ++++++++++++++---- crates/zed/src/menus.rs | 1 + crates/zed/src/zed.rs | 3 --- 5 files changed, 17 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0f19d4455f957463f61e8db34ff9fdb135ed4f3b..ade18d799eca665a9c4c03508a3fda7552f13748 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1259,6 +1259,7 @@ dependencies = [ "collections", "context_menu", "editor", + "feedback", "futures 0.3.25", "fuzzy", "gpui", diff --git a/crates/collab_ui/Cargo.toml b/crates/collab_ui/Cargo.toml index 899f8cc8b4204dc0c2b6d0c060aafb1a42e7e907..2afeb8ad8ae755b1f8b554d8e4a9bc15732767f3 100644 --- a/crates/collab_ui/Cargo.toml +++ b/crates/collab_ui/Cargo.toml @@ -29,6 +29,7 @@ clock = { path = "../clock" } collections = { path = "../collections" } context_menu = { path = "../context_menu" } editor = { path = "../editor" } +feedback = { path = "../feedback" } fuzzy = { path = "../fuzzy" } gpui = { path = "../gpui" } menu = { path = "../menu" } diff --git a/crates/collab_ui/src/collab_titlebar_item.rs b/crates/collab_ui/src/collab_titlebar_item.rs index c838f6a55fc3ec716571a9261066473910a6f413..4968097ac5e163261e0002c939ed4beaad6103de 100644 --- a/crates/collab_ui/src/collab_titlebar_item.rs +++ b/crates/collab_ui/src/collab_titlebar_item.rs @@ -304,12 +304,22 @@ impl CollabTitlebarItem { label: "Sign out".into(), action: Box::new(SignOut), }, + ContextMenuItem::Item { + label: "Give Feedback".into(), + action: Box::new(feedback::feedback_editor::GiveFeedback), + }, ] } else { - vec![ContextMenuItem::Item { - label: "Sign in".into(), - action: Box::new(Authenticate), - }] + vec![ + ContextMenuItem::Item { + label: "Sign in".into(), + action: Box::new(Authenticate), + }, + ContextMenuItem::Item { + label: "Give Feedback".into(), + action: Box::new(feedback::feedback_editor::GiveFeedback), + }, + ] }; user_menu.show( diff --git a/crates/zed/src/menus.rs b/crates/zed/src/menus.rs index bb519c7a9505bc2de07fa60c70014be3b4fbc169..2c16d4ba8bedb12033e6d1163c9ff59c2fc48a14 100644 --- a/crates/zed/src/menus.rs +++ b/crates/zed/src/menus.rs @@ -140,6 +140,7 @@ pub fn menus() -> Vec> { MenuItem::action("View Telemetry Log", crate::OpenTelemetryLog), MenuItem::action("View Dependency Licenses", crate::OpenLicenses), MenuItem::separator(), + MenuItem::action("Give us feedback", feedback::feedback_editor::GiveFeedback), MenuItem::action( "Copy System Specs Into Clipboard", feedback::CopySystemSpecsIntoClipboard, diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index 26989102e4221dcca3fdcef447271d4b232a7feb..d742c733e52e275aa26f10ee9034831bc66528ad 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -340,10 +340,7 @@ pub fn initialize_workspace( activity_indicator::ActivityIndicator::new(workspace, app_state.languages.clone(), cx); let active_buffer_language = cx.add_view(|_| language_selector::ActiveBufferLanguage::new()); let cursor_position = cx.add_view(|_| editor::items::CursorPosition::new()); - let feedback_button = - cx.add_view(|_| feedback::deploy_feedback_button::DeployFeedbackButton {}); workspace.status_bar().update(cx, |status_bar, cx| { - status_bar.add_left_item(feedback_button, cx); status_bar.add_left_item(diagnostic_summary, cx); status_bar.add_left_item(activity_indicator, cx); status_bar.add_right_item(active_buffer_language, cx); From 9398de6a577f3d88e08135f50027e21f80cf8b4e Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Fri, 10 Mar 2023 13:15:36 -0800 Subject: [PATCH 86/93] Add feedback for telemetry item when there's no data --- crates/zed/src/zed.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index 20dbcdb7efc9e8a60aee3499244687523798b98f..bebc1954640995250f4e57af92a1a068c300e5c3 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -577,8 +577,13 @@ fn open_telemetry_log_file( workspace.with_local_workspace(&app_state.clone(), cx, move |_, cx| { cx.spawn_weak(|workspace, mut cx| async move { let workspace = workspace.upgrade(&cx)?; - let path = app_state.client.telemetry_log_file_path()?; - let log = app_state.fs.load(&path).await.log_err()?; + + async fn fetch_log_string(app_state: &Arc) -> Option { + let path = app_state.client.telemetry_log_file_path()?; + app_state.fs.load(&path).await.log_err() + } + + let log = fetch_log_string(&app_state).await.unwrap_or_else(|| "// No data has been collected yet".to_string()); const MAX_TELEMETRY_LOG_LEN: usize = 5 * 1024 * 1024; let mut start_offset = log.len().saturating_sub(MAX_TELEMETRY_LOG_LEN); From 0a5cf4b83174816e02bc72a456e9e545a96261ea Mon Sep 17 00:00:00 2001 From: Julia Date: Fri, 10 Mar 2023 16:54:57 -0500 Subject: [PATCH 87/93] Avoid panic scanning recursive symlink before gitignore is encountered --- crates/project/src/worktree.rs | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/crates/project/src/worktree.rs b/crates/project/src/worktree.rs index 8b622ab607db49f6f5b54845ccf7d70397752225..40b8881067f355517fe9695075a59fc1fa15f97d 100644 --- a/crates/project/src/worktree.rs +++ b/crates/project/src/worktree.rs @@ -2361,7 +2361,7 @@ impl BackgroundScanner { job: &ScanJob, ) -> Result<()> { let mut new_entries: Vec = Vec::new(); - let mut new_jobs: Vec = Vec::new(); + let mut new_jobs: Vec> = Vec::new(); let mut ignore_stack = job.ignore_stack.clone(); let mut new_ignore = None; @@ -2374,6 +2374,7 @@ impl BackgroundScanner { continue; } }; + let child_name = child_abs_path.file_name().unwrap(); let child_path: Arc = job.path.join(child_name).into(); let child_metadata = match self.fs.metadata(&child_abs_path).await { @@ -2412,12 +2413,15 @@ impl BackgroundScanner { let entry_abs_path = self.abs_path().join(&entry.path); entry.is_ignored = ignore_stack.is_abs_path_ignored(&entry_abs_path, entry.is_dir()); + if entry.is_dir() { - new_jobs.next().unwrap().ignore_stack = if entry.is_ignored { - IgnoreStack::all() - } else { - ignore_stack.clone() - }; + if let Some(job) = new_jobs.next().expect("Missing scan job for entry") { + job.ignore_stack = if entry.is_ignored { + IgnoreStack::all() + } else { + ignore_stack.clone() + }; + } } } } @@ -2433,10 +2437,12 @@ impl BackgroundScanner { let is_ignored = ignore_stack.is_abs_path_ignored(&child_abs_path, true); child_entry.is_ignored = is_ignored; + // Avoid recursing until crash in the case of a recursive symlink if !job.ancestor_inodes.contains(&child_entry.inode) { let mut ancestor_inodes = job.ancestor_inodes.clone(); ancestor_inodes.insert(child_entry.inode); - new_jobs.push(ScanJob { + + new_jobs.push(Some(ScanJob { abs_path: child_abs_path, path: child_path, ignore_stack: if is_ignored { @@ -2446,7 +2452,9 @@ impl BackgroundScanner { }, ancestor_inodes, scan_queue: job.scan_queue.clone(), - }); + })); + } else { + new_jobs.push(None); } } else { child_entry.is_ignored = ignore_stack.is_abs_path_ignored(&child_abs_path, false); @@ -2461,8 +2469,11 @@ impl BackgroundScanner { new_ignore, self.fs.as_ref(), ); + for new_job in new_jobs { - job.scan_queue.send(new_job).await.unwrap(); + if let Some(new_job) = new_job { + job.scan_queue.send(new_job).await.unwrap(); + } } Ok(()) From adf94a16812b979206ce8ad5d0593c32cf696c2d Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Fri, 10 Mar 2023 14:43:28 -0800 Subject: [PATCH 88/93] Switch from using the key window to the main window mac platform API When the help menu is open, the help menu's search field is the key window, and this was causing menu item action resolution to fail co-authored-by: Max --- crates/gpui/src/app.rs | 2 +- crates/gpui/src/app/menu.rs | 6 +++--- crates/gpui/src/platform.rs | 2 +- crates/gpui/src/platform/mac/platform.rs | 4 ++-- crates/gpui/src/platform/mac/window.rs | 8 ++++---- crates/gpui/src/platform/test.rs | 2 +- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/crates/gpui/src/app.rs b/crates/gpui/src/app.rs index 0397032de89964e6a095039d315b614be2906102..cc8facafc619d3abc8f2c1e1f06aa0e6da79313b 100644 --- a/crates/gpui/src/app.rs +++ b/crates/gpui/src/app.rs @@ -1294,7 +1294,7 @@ impl MutableAppContext { pub fn is_action_available(&self, action: &dyn Action) -> bool { let action_type = action.as_any().type_id(); - if let Some(window_id) = self.cx.platform.key_window_id() { + if let Some(window_id) = self.cx.platform.main_window_id() { if let Some(focused_view_id) = self.focused_view_id(window_id) { for view_id in self.ancestors(window_id, focused_view_id) { if let Some(view) = self.views.get(&(window_id, view_id)) { diff --git a/crates/gpui/src/app/menu.rs b/crates/gpui/src/app/menu.rs index 5fe307a7c10f0bc3a6a9f64c5aa52a4aa69d48a0..b0965539a515e0fc53b169a48bf950c838e92896 100644 --- a/crates/gpui/src/app/menu.rs +++ b/crates/gpui/src/app/menu.rs @@ -77,9 +77,9 @@ pub(crate) fn setup_menu_handlers(foreground_platform: &dyn ForegroundPlatform, let cx = app.0.clone(); move |action| { let mut cx = cx.borrow_mut(); - if let Some(key_window_id) = cx.cx.platform.key_window_id() { - if let Some(view_id) = cx.focused_view_id(key_window_id) { - cx.handle_dispatch_action_from_effect(key_window_id, Some(view_id), action); + if let Some(main_window_id) = cx.cx.platform.main_window_id() { + if let Some(view_id) = cx.focused_view_id(main_window_id) { + cx.handle_dispatch_action_from_effect(main_window_id, Some(view_id), action); return; } } diff --git a/crates/gpui/src/platform.rs b/crates/gpui/src/platform.rs index 76c2707d2638823e057eecdd30a2614d592f717f..4c1ba49690c43d6b0e0f033b2d2177311a9e8873 100644 --- a/crates/gpui/src/platform.rs +++ b/crates/gpui/src/platform.rs @@ -58,7 +58,7 @@ pub trait Platform: Send + Sync { options: WindowOptions, executor: Rc, ) -> Box; - fn key_window_id(&self) -> Option; + fn main_window_id(&self) -> Option; fn add_status_item(&self) -> Box; diff --git a/crates/gpui/src/platform/mac/platform.rs b/crates/gpui/src/platform/mac/platform.rs index aeec02c8caa230c9be46025f0d160ef371f67f06..9bb6430c644cdaea1b29610b3d01637e967b721c 100644 --- a/crates/gpui/src/platform/mac/platform.rs +++ b/crates/gpui/src/platform/mac/platform.rs @@ -587,8 +587,8 @@ impl platform::Platform for MacPlatform { Box::new(Window::open(id, options, executor, self.fonts())) } - fn key_window_id(&self) -> Option { - Window::key_window_id() + fn main_window_id(&self) -> Option { + Window::main_window_id() } fn add_status_item(&self) -> Box { diff --git a/crates/gpui/src/platform/mac/window.rs b/crates/gpui/src/platform/mac/window.rs index 19173707fb13f1fa732b3bc20659dd6f0e6a4991..a0c1820368c802b5453ed33c2d8f1e50322228d8 100644 --- a/crates/gpui/src/platform/mac/window.rs +++ b/crates/gpui/src/platform/mac/window.rs @@ -604,12 +604,12 @@ impl Window { } } - pub fn key_window_id() -> Option { + pub fn main_window_id() -> Option { unsafe { let app = NSApplication::sharedApplication(nil); - let key_window: id = msg_send![app, keyWindow]; - if msg_send![key_window, isKindOfClass: WINDOW_CLASS] { - let id = get_window_state(&*key_window).borrow().id; + let main_window: id = msg_send![app, mainWindow]; + if msg_send![main_window, isKindOfClass: WINDOW_CLASS] { + let id = get_window_state(&*main_window).borrow().id; Some(id) } else { None diff --git a/crates/gpui/src/platform/test.rs b/crates/gpui/src/platform/test.rs index 194684bd12917daf64fa4e56c763b33663640abd..a3532dd96e1298fedaa6ffea2214a026cc46e085 100644 --- a/crates/gpui/src/platform/test.rs +++ b/crates/gpui/src/platform/test.rs @@ -157,7 +157,7 @@ impl super::Platform for Platform { })) } - fn key_window_id(&self) -> Option { + fn main_window_id(&self) -> Option { None } From ece2af1e223b299b329d4b2b1762daa8a47798c2 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Fri, 10 Mar 2023 15:36:20 -0800 Subject: [PATCH 89/93] Fix a corner case in available action resolution Add tests for new keybinding resolution behavior co-authored-by: max --- crates/gpui/src/app.rs | 152 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 135 insertions(+), 17 deletions(-) diff --git a/crates/gpui/src/app.rs b/crates/gpui/src/app.rs index 2f29815f0328b29331ecdbab2291189d0372299a..1dbea615edccd859c571d6cd7b013867bbb1e509 100644 --- a/crates/gpui/src/app.rs +++ b/crates/gpui/src/app.rs @@ -1241,12 +1241,12 @@ impl MutableAppContext { action: &dyn Action, ) -> Option> { let mut contexts = Vec::new(); - let mut highest_handler = None; + let mut handler_depth = None; for (i, view_id) in self.ancestors(window_id, view_id).enumerate() { if let Some(view) = self.views.get(&(window_id, view_id)) { if let Some(actions) = self.actions.get(&view.as_any().type_id()) { if actions.contains_key(&action.as_any().type_id()) { - highest_handler = Some(i); + handler_depth = Some(i); } } contexts.push(view.keymap_context(self)); @@ -1254,13 +1254,13 @@ impl MutableAppContext { } if self.global_actions.contains_key(&action.as_any().type_id()) { - highest_handler = Some(contexts.len()) + handler_depth = Some(contexts.len()) } self.keystroke_matcher .bindings_for_action_type(action.as_any().type_id()) .find_map(|b| { - highest_handler + handler_depth .map(|highest_handler| { if (0..=highest_handler).any(|depth| b.match_context(&contexts[depth..])) { Some(b.keystrokes().into()) @@ -1278,45 +1278,40 @@ impl MutableAppContext { view_id: usize, ) -> impl Iterator, SmallVec<[&Binding; 1]>)> { let mut contexts = Vec::new(); - let mut handler_depth_by_action_type = HashMap::>::default(); - for (i, view_id) in self.ancestors(window_id, view_id).enumerate() { + let mut handler_depths_by_action_type = HashMap::::default(); + for (depth, view_id) in self.ancestors(window_id, view_id).enumerate() { if let Some(view) = self.views.get(&(window_id, view_id)) { contexts.push(view.keymap_context(self)); let view_type = view.as_any().type_id(); if let Some(actions) = self.actions.get(&view_type) { - handler_depth_by_action_type.extend( + handler_depths_by_action_type.extend( actions .keys() .copied() - .map(|action_type| (action_type, Some(i))), + .map(|action_type| (action_type, depth)), ); } } } - handler_depth_by_action_type.extend( + handler_depths_by_action_type.extend( self.global_actions .keys() .copied() - .map(|action_type| (action_type, None)), + .map(|action_type| (action_type, contexts.len())), ); self.action_deserializers .iter() .filter_map(move |(name, (type_id, deserialize))| { - if let Some(action_depth) = handler_depth_by_action_type.get(type_id) { + if let Some(action_depth) = handler_depths_by_action_type.get(type_id).copied() { Some(( *name, deserialize("{}").ok()?, self.keystroke_matcher .bindings_for_action_type(*type_id) .filter(|b| { - if let Some(action_depth) = *action_depth { - (0..=action_depth) - .any(|depth| b.match_context(&contexts[depth..])) - } else { - true - } + (0..=action_depth).any(|depth| b.match_context(&contexts[depth..])) }) .collect(), )) @@ -5321,6 +5316,7 @@ impl Subscription { mod tests { use super::*; use crate::{actions, elements::*, impl_actions, MouseButton, MouseButtonEvent}; + use itertools::Itertools; use postage::{sink::Sink, stream::Stream}; use serde::Deserialize; use smol::future::poll_once; @@ -6751,6 +6747,128 @@ mod tests { actions.borrow_mut().clear(); } + #[crate::test(self)] + fn test_keystrokes_for_action(cx: &mut MutableAppContext) { + actions!(test, [Action1, Action2, GlobalAction]); + + struct View1 {} + struct View2 {} + + impl Entity for View1 { + type Event = (); + } + impl Entity for View2 { + type Event = (); + } + + impl super::View for View1 { + fn render(&mut self, _: &mut RenderContext) -> ElementBox { + Empty::new().boxed() + } + fn ui_name() -> &'static str { + "View1" + } + } + impl super::View for View2 { + fn render(&mut self, _: &mut RenderContext) -> ElementBox { + Empty::new().boxed() + } + fn ui_name() -> &'static str { + "View2" + } + } + + let (window_id, view_1) = cx.add_window(Default::default(), |_| View1 {}); + let view_2 = cx.add_view(&view_1, |cx| { + cx.focus_self(); + View2 {} + }); + + cx.add_action(|_: &mut View1, _: &Action1, _cx| {}); + cx.add_action(|_: &mut View2, _: &Action2, _cx| {}); + cx.add_global_action(|_: &GlobalAction, _| {}); + + cx.add_bindings(vec![ + Binding::new("a", Action1, Some("View1")), + Binding::new("b", Action2, Some("View1 > View2")), + Binding::new("c", GlobalAction, Some("View3")), // View 3 does not exist + ]); + + // Sanity check + assert_eq!( + cx.keystrokes_for_action(window_id, view_1.id(), &Action1) + .unwrap() + .as_slice(), + &[Keystroke::parse("a").unwrap()] + ); + assert_eq!( + cx.keystrokes_for_action(window_id, view_2.id(), &Action2) + .unwrap() + .as_slice(), + &[Keystroke::parse("b").unwrap()] + ); + + // The 'a' keystroke propagates up the view tree from view_2 + // to view_1. The action, Action1, is handled by view_1. + assert_eq!( + cx.keystrokes_for_action(window_id, view_2.id(), &Action1) + .unwrap() + .as_slice(), + &[Keystroke::parse("a").unwrap()] + ); + + // Actions that are handled below the current view don't have bindings + assert_eq!( + cx.keystrokes_for_action(window_id, view_1.id(), &Action2), + None + ); + + // Actions that are handled in other branches of the tree should not have a binding + assert_eq!( + cx.keystrokes_for_action(window_id, view_2.id(), &GlobalAction), + None + ); + + // Produces a list of actions and keybindings + fn available_actions( + window_id: usize, + view_id: usize, + cx: &mut MutableAppContext, + ) -> Vec<(&'static str, Vec)> { + cx.available_actions(window_id, view_id) + .map(|(action_name, _, bindings)| { + ( + action_name, + bindings + .iter() + .map(|binding| binding.keystrokes()[0].clone()) + .collect::>(), + ) + }) + .sorted_by(|(name1, _), (name2, _)| name1.cmp(name2)) + .collect() + } + + // Check that global actions do not have a binding, even if a binding does exist in another view + assert_eq!( + &available_actions(window_id, view_1.id(), cx), + &[ + ("test::Action1", vec![Keystroke::parse("a").unwrap()]), + ("test::GlobalAction", vec![]) + ], + ); + + // Check that view 1 actions and bindings are available even when called from view 2 + assert_eq!( + &available_actions(window_id, view_2.id(), cx), + &[ + ("test::Action1", vec![Keystroke::parse("a").unwrap()]), + ("test::Action2", vec![Keystroke::parse("b").unwrap()]), + ("test::GlobalAction", vec![]), + ], + ); + } + #[crate::test(self)] async fn test_model_condition(cx: &mut TestAppContext) { struct Counter(usize); From 11d8394af249f1a2f2641bac9454c204a0ef1b86 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Fri, 10 Mar 2023 15:54:42 -0800 Subject: [PATCH 90/93] Fix the terminal icon button to only be active when a terminal is focused --- crates/workspace/src/terminal_button.rs | 26 ++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/crates/workspace/src/terminal_button.rs b/crates/workspace/src/terminal_button.rs index 118df7cab15686085647427f40db65451cf99987..b4ad662c94cba2d69c3c39230b45beb1726fc825 100644 --- a/crates/workspace/src/terminal_button.rs +++ b/crates/workspace/src/terminal_button.rs @@ -11,7 +11,6 @@ pub struct TerminalButton { workspace: WeakViewHandle, } -// TODO: Rename this to `DeployTerminalButton` impl TerminalButton { pub fn new(workspace: ViewHandle, cx: &mut ViewContext) -> Self { // When terminal moves, redraw so that the icon and toggle status matches. @@ -39,6 +38,13 @@ impl View for TerminalButton { return Empty::new().boxed(); } + let focused_view = cx.focused_view_id(cx.window_id()); + + // FIXME: Don't hardcode "Terminal" in here + let active = focused_view + .map(|view| cx.view_ui_name(cx.window_id(), view) == Some("Terminal")) + .unwrap_or(false); + // let workspace = workspace.unwrap(); let theme = cx.global::().theme.clone(); @@ -50,7 +56,7 @@ impl View for TerminalButton { .status_bar .sidebar_buttons .item - .style_for(state, true); + .style_for(state, active); Svg::new("icons/terminal_12.svg") .with_color(style.icon_color) @@ -63,14 +69,10 @@ impl View for TerminalButton { } }) .with_cursor_style(CursorStyle::PointingHand) - .on_up(MouseButton::Left, move |_, _| { - // TODO: Do we need this stuff? - // let dock_pane = workspace.read(cx.app).dock_pane(); - // let drop_index = dock_pane.read(cx.app).items_len() + 1; - // handle_dropped_item(event, &dock_pane.downgrade(), drop_index, false, None, cx); - }) - .on_click(MouseButton::Left, |_, cx| { - cx.dispatch_action(FocusDock); + .on_click(MouseButton::Left, move |_, cx| { + if !active { + cx.dispatch_action(FocusDock); + } }) .with_tooltip::( 0, @@ -84,5 +86,7 @@ impl View for TerminalButton { } impl StatusItemView for TerminalButton { - fn set_active_pane_item(&mut self, _: Option<&dyn ItemHandle>, _: &mut ViewContext) {} + fn set_active_pane_item(&mut self, _: Option<&dyn ItemHandle>, cx: &mut ViewContext) { + cx.notify(); + } } From c8de738972142fba2fefe7ea59aff501d93d5bb6 Mon Sep 17 00:00:00 2001 From: Mikayla Maki Date: Fri, 10 Mar 2023 16:19:33 -0800 Subject: [PATCH 91/93] Align feedback button styles with other sidebar buttons Make feedback button reflect whether you're in a feedback buffer --- crates/feedback/src/deploy_feedback_button.rs | 47 +++++++++++++++---- crates/theme/src/theme.rs | 1 - crates/zed/src/zed.rs | 3 ++ styles/src/styleTree/statusBar.ts | 9 ---- 4 files changed, 41 insertions(+), 19 deletions(-) diff --git a/crates/feedback/src/deploy_feedback_button.rs b/crates/feedback/src/deploy_feedback_button.rs index 7519d2d06e649164cdd742dca4d3dc92e51d7899..222c542eed4dba57e31a1b61d1099b4a72f02e24 100644 --- a/crates/feedback/src/deploy_feedback_button.rs +++ b/crates/feedback/src/deploy_feedback_button.rs @@ -2,39 +2,58 @@ use gpui::{elements::*, CursorStyle, Entity, MouseButton, RenderContext, View, V use settings::Settings; use workspace::{item::ItemHandle, StatusItemView}; -use crate::feedback_editor::GiveFeedback; +use crate::feedback_editor::{FeedbackEditor, GiveFeedback}; -pub struct DeployFeedbackButton; +pub struct DeployFeedbackButton { + active: bool, +} impl Entity for DeployFeedbackButton { type Event = (); } +impl DeployFeedbackButton { + pub fn new() -> Self { + DeployFeedbackButton { active: false } + } +} + impl View for DeployFeedbackButton { fn ui_name() -> &'static str { "DeployFeedbackButton" } fn render(&mut self, cx: &mut RenderContext<'_, Self>) -> ElementBox { + let active = self.active; Stack::new() .with_child( MouseEventHandler::::new(0, cx, |state, cx| { let theme = &cx.global::().theme; - let style = &theme.workspace.status_bar.feedback.style_for(state, false); + let style = &theme + .workspace + .status_bar + .sidebar_buttons + .item + .style_for(state, active); + Svg::new("icons/speech_bubble_12.svg") - .with_color(style.color) + .with_color(style.icon_color) .constrained() - .with_width(style.icon_width) + .with_width(style.icon_size) .aligned() .constrained() - .with_width(style.button_width) - .with_height(style.button_width) + .with_width(style.icon_size) + .with_height(style.icon_size) .contained() .with_style(style.container) .boxed() }) .with_cursor_style(CursorStyle::PointingHand) - .on_click(MouseButton::Left, |_, cx| cx.dispatch_action(GiveFeedback)) + .on_click(MouseButton::Left, move |_, cx| { + if !active { + cx.dispatch_action(GiveFeedback) + } + }) .boxed(), ) .boxed() @@ -42,5 +61,15 @@ impl View for DeployFeedbackButton { } impl StatusItemView for DeployFeedbackButton { - fn set_active_pane_item(&mut self, _: Option<&dyn ItemHandle>, _: &mut ViewContext) {} + fn set_active_pane_item(&mut self, item: Option<&dyn ItemHandle>, cx: &mut ViewContext) { + if let Some(item) = item { + if let Some(_) = item.downcast::() { + self.active = true; + cx.notify(); + return; + } + } + self.active = false; + cx.notify(); + } } diff --git a/crates/theme/src/theme.rs b/crates/theme/src/theme.rs index 87504d6cd98423424d6994e7f06d6ef1f2e666ed..70ee22d37d4d98e74b90a09c2848a52326280fab 100644 --- a/crates/theme/src/theme.rs +++ b/crates/theme/src/theme.rs @@ -281,7 +281,6 @@ pub struct StatusBar { pub auto_update_progress_message: TextStyle, pub auto_update_done_message: TextStyle, pub lsp_status: Interactive, - pub feedback: Interactive, pub sidebar_buttons: StatusBarSidebarButtons, pub diagnostic_summary: Interactive, pub diagnostic_message: Interactive, diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index d742c733e52e275aa26f10ee9034831bc66528ad..79ec9b411857e44475ff379927561efae32e0ae7 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -339,10 +339,13 @@ pub fn initialize_workspace( let activity_indicator = activity_indicator::ActivityIndicator::new(workspace, app_state.languages.clone(), cx); let active_buffer_language = cx.add_view(|_| language_selector::ActiveBufferLanguage::new()); + let feedback_button = + cx.add_view(|_| feedback::deploy_feedback_button::DeployFeedbackButton::new()); let cursor_position = cx.add_view(|_| editor::items::CursorPosition::new()); workspace.status_bar().update(cx, |status_bar, cx| { status_bar.add_left_item(diagnostic_summary, cx); status_bar.add_left_item(activity_indicator, cx); + status_bar.add_right_item(feedback_button, cx); status_bar.add_right_item(active_buffer_language, cx); status_bar.add_right_item(cursor_position, cx); }); diff --git a/styles/src/styleTree/statusBar.ts b/styles/src/styleTree/statusBar.ts index e5c07c07c2b1598a04e31ec34b20fd7a16afc9fe..9fa427d302f19008f169c77e847cf67031e63562 100644 --- a/styles/src/styleTree/statusBar.ts +++ b/styles/src/styleTree/statusBar.ts @@ -51,15 +51,6 @@ export default function statusBar(colorScheme: ColorScheme) { ...text(layer, "sans"), hover: text(layer, "sans", "hovered"), }, - feedback: { - margin: { left: 2 }, - color: foreground(layer, "variant"), - iconWidth: 14, - buttonWidth: 14, - hover: { - color: foreground(layer, "on"), - }, - }, diagnosticSummary: { height: 20, iconWidth: 16, From ff1c7db38fb3c7ceaae347b8fae6f7c4c9264eb0 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 10 Mar 2023 16:36:03 -0800 Subject: [PATCH 92/93] collab 0.7.1 --- Cargo.lock | 2 +- crates/collab/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 21d78cd5994dfecf805b0cd0c83738e2f8b24912..384ded5b3ee428be6efdc446a51cd4a53ae7dc6c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1188,7 +1188,7 @@ dependencies = [ [[package]] name = "collab" -version = "0.7.0" +version = "0.7.1" dependencies = [ "anyhow", "async-tungstenite", diff --git a/crates/collab/Cargo.toml b/crates/collab/Cargo.toml index a2ad7d73430f4bbd8a350e06e1de775f999c4880..0f06a14b68c1b0e1998554d249fa03c509f2ef2f 100644 --- a/crates/collab/Cargo.toml +++ b/crates/collab/Cargo.toml @@ -3,7 +3,7 @@ authors = ["Nathan Sobo "] default-run = "collab" edition = "2021" name = "collab" -version = "0.7.0" +version = "0.7.1" publish = false [[bin]] From e8b3d4e0fa8c95b1078bbda05f5fde981d5e9b2e Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 10 Mar 2023 17:19:16 -0800 Subject: [PATCH 93/93] Encode db-max-connections env var as a string in k8s manifest --- crates/collab/k8s/manifest.template.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/collab/k8s/manifest.template.yml b/crates/collab/k8s/manifest.template.yml index 75c7aa989d9797f28c57d1ee1f5cab90b28bcfeb..0662a287d4b4541f4285e9b4ba7c3c0a2bdafcbf 100644 --- a/crates/collab/k8s/manifest.template.yml +++ b/crates/collab/k8s/manifest.template.yml @@ -81,7 +81,7 @@ spec: name: database key: url - name: DATABASE_MAX_CONNECTIONS - value: ${DATABASE_MAX_CONNECTIONS} + value: "${DATABASE_MAX_CONNECTIONS}" - name: API_TOKEN valueFrom: secretKeyRef: