From 3ab20626147a0bbe4739e6bdb8faf8ee78137b22 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 4 Jan 2024 16:15:32 +0100 Subject: [PATCH 01/13] Fix border rendering After implementing it a while ago, our previous interpolation scheme didn't really make sense to me and was causing borders to be rendered incorrectly. We don't really draw backgrounds and borders as part of the same draw call anymore, but it seemed reasonable to have a correct implementation in the shader anyway. This commit uses Porter-Duff compositing (i.e., `over`) to produce a color that is the result of superimposing the border on top of the background. Then, we linearly interpolate towards the background color as we slide out of the border and into the background. --- crates/gpui/src/platform/mac/shaders.metal | 30 +++++++++++----------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/crates/gpui/src/platform/mac/shaders.metal b/crates/gpui/src/platform/mac/shaders.metal index aba01b9d5b..264fa55134 100644 --- a/crates/gpui/src/platform/mac/shaders.metal +++ b/crates/gpui/src/platform/mac/shaders.metal @@ -16,6 +16,7 @@ float gaussian(float x, float sigma); float2 erf(float2 x); float blur_along_x(float x, float y, float sigma, float corner, float2 half_size); +float4 over(float4 below, float4 above); struct QuadVertexOutput { float4 position [[position]]; @@ -108,21 +109,11 @@ fragment float4 quad_fragment(QuadFragmentInput input [[stage_in]], color = input.background_color; } else { float inset_distance = distance + border_width; - - // Decrease border's opacity as we move inside the background. - input.border_color.a *= 1. - saturate(0.5 - inset_distance); - - // Alpha-blend the border and the background. - float output_alpha = input.border_color.a + - input.background_color.a * (1. - input.border_color.a); - float3 premultiplied_border_rgb = - input.border_color.rgb * input.border_color.a; - float3 premultiplied_background_rgb = - input.background_color.rgb * input.background_color.a; - float3 premultiplied_output_rgb = - premultiplied_border_rgb + - premultiplied_background_rgb * (1. - input.border_color.a); - color = float4(premultiplied_output_rgb, output_alpha); + // Blend the border on top of the background and then linearly interpolate + // between the two as we slide inside the background. + float4 blended_border = over(input.background_color, input.border_color); + color = mix(blended_border, input.background_color, + saturate(0.5 - inset_distance)); } return color * float4(1., 1., 1., saturate(0.5 - distance)); @@ -653,3 +644,12 @@ float4 distance_from_clip_rect(float2 unit_vertex, Bounds_ScaledPixels bounds, position.y - clip_bounds.origin.y, clip_bounds.origin.y + clip_bounds.size.height - position.y); } + +float4 over(float4 below, float4 above) { + float4 result; + float alpha = above.a + below.a * (1.0 - above.a); + result.rgb = + (above.rgb * above.a + below.rgb * below.a * (1.0 - above.a)) / alpha; + result.a = alpha; + return result; +} From 5a1509ef269b608f95d7f73355f533ead852de72 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 4 Jan 2024 16:37:13 +0100 Subject: [PATCH 02/13] Re-enable key bindings for `AssistantPanel` --- crates/assistant/src/assistant_panel.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/assistant/src/assistant_panel.rs b/crates/assistant/src/assistant_panel.rs index 3625b64e32..9221d87f60 100644 --- a/crates/assistant/src/assistant_panel.rs +++ b/crates/assistant/src/assistant_panel.rs @@ -1157,6 +1157,7 @@ impl Render for AssistantPanel { }); v_stack() + .key_context("AssistantPanel") .size_full() .on_action(cx.listener(|this, _: &workspace::NewFile, cx| { this.new_conversation(cx); From a7550de8c57c4ee143ed696de3362314f0c3b305 Mon Sep 17 00:00:00 2001 From: Julia Date: Wed, 3 Jan 2024 14:36:10 -0500 Subject: [PATCH 03/13] Show pointer hand on tab & give last tab border right --- crates/ui/src/components/tab.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/ui/src/components/tab.rs b/crates/ui/src/components/tab.rs index 9bafb0c0bb..351c851bb9 100644 --- a/crates/ui/src/components/tab.rs +++ b/crates/ui/src/components/tab.rs @@ -126,13 +126,14 @@ impl RenderOnce for Tab { if self.selected { this.border_l().border_r().pb_px() } else { - this.pr_px().pl_px().border_b() + this.pr_px().pl_px().border_b().border_r() } } TabPosition::Middle(Ordering::Equal) => this.border_l().border_r().pb_px(), TabPosition::Middle(Ordering::Less) => this.border_l().pr_px().border_b(), TabPosition::Middle(Ordering::Greater) => this.border_r().pl_px().border_b(), }) + .cursor_pointer() .child( h_stack() .group("") From 6f4a08ba5a96a13793449d094dfd78a34b237440 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 4 Jan 2024 17:25:02 +0100 Subject: [PATCH 04/13] Prevent scrolling editor and resizing panels at the same time This fixes a bug that would cause Zed to never stop resizing panels when the drag handle overlapped with an editor scrollbar. Co-Authored-By: Marshall --- crates/editor/src/element.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index ab29f6c8b2..b1a3e73d6a 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -1230,6 +1230,14 @@ impl EditorElement { return; } + // If a drag took place after we started dragging the scrollbar, + // cancel the scrollbar drag. + if cx.has_active_drag() { + self.editor.update(cx, |editor, cx| { + editor.scroll_manager.set_is_dragging_scrollbar(false, cx); + }); + } + let top = bounds.origin.y; let bottom = bounds.lower_left().y; let right = bounds.lower_right().x; From 4e310b99aa0da7d5d231dbacc398222aa297e760 Mon Sep 17 00:00:00 2001 From: Conrad Irwin Date: Thu, 4 Jan 2024 09:45:39 -0700 Subject: [PATCH 05/13] Implement "open in terminal" --- Cargo.lock | 2 +- crates/project_panel/src/project_panel.rs | 29 ++++++++--------------- 2 files changed, 11 insertions(+), 20 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1d0af3c008..13d4be6233 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9514,7 +9514,7 @@ dependencies = [ [[package]] name = "zed" -version = "0.119.0" +version = "0.120.0" dependencies = [ "activity_indicator", "ai", diff --git a/crates/project_panel/src/project_panel.rs b/crates/project_panel/src/project_panel.rs index 6f438098b7..e0bee14df2 100644 --- a/crates/project_panel/src/project_panel.rs +++ b/crates/project_panel/src/project_panel.rs @@ -971,25 +971,16 @@ impl ProjectPanel { } } - fn open_in_terminal(&mut self, _: &OpenInTerminal, _cx: &mut ViewContext) { - todo!() - // if let Some((worktree, entry)) = self.selected_entry(cx) { - // let window = cx.window(); - // let view_id = cx.view_id(); - // let path = worktree.abs_path().join(&entry.path); - - // cx.app_context() - // .spawn(|mut cx| async move { - // window.dispatch_action( - // view_id, - // &workspace::OpenTerminal { - // working_directory: path, - // }, - // &mut cx, - // ); - // }) - // .detach(); - // } + fn open_in_terminal(&mut self, _: &OpenInTerminal, cx: &mut ViewContext) { + if let Some((worktree, entry)) = self.selected_entry(cx) { + let path = worktree.abs_path().join(&entry.path); + cx.dispatch_action( + workspace::OpenTerminal { + working_directory: path, + } + .boxed_clone(), + ) + } } pub fn new_search_in_directory( From 90fc1ebaf6acfac4d8b3ab8e18871216335c1a01 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Thu, 4 Jan 2024 09:53:57 -0800 Subject: [PATCH 06/13] Fix version comparison in auto update Co-authored-by: Antonio Scandurra --- crates/auto_update/src/auto_update.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/auto_update/src/auto_update.rs b/crates/auto_update/src/auto_update.rs index 691b83479f..a2a90d4f2f 100644 --- a/crates/auto_update/src/auto_update.rs +++ b/crates/auto_update/src/auto_update.rs @@ -270,7 +270,7 @@ impl AutoUpdater { ReleaseChannel::Nightly => cx .try_read_global::(|sha, _| release.version != sha.0) .unwrap_or(true), - _ => release.version.parse::()? <= current_version, + _ => release.version.parse::()? > current_version, }; if !should_download { From 3d1023ef52a4041c355af370e929eab713c5c3a7 Mon Sep 17 00:00:00 2001 From: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Date: Thu, 4 Jan 2024 19:24:22 +0100 Subject: [PATCH 07/13] lsp: Do not cache initialization options --- crates/language/src/language.rs | 3 --- crates/project/src/project.rs | 26 ++++++++++++-------------- 2 files changed, 12 insertions(+), 17 deletions(-) diff --git a/crates/language/src/language.rs b/crates/language/src/language.rs index 5564481c6b..366d2b0098 100644 --- a/crates/language/src/language.rs +++ b/crates/language/src/language.rs @@ -113,7 +113,6 @@ pub struct LanguageServerName(pub Arc); pub struct CachedLspAdapter { pub name: LanguageServerName, pub short_name: &'static str, - pub initialization_options: Option, pub disk_based_diagnostic_sources: Vec, pub disk_based_diagnostics_progress_token: Option, pub language_ids: HashMap, @@ -125,7 +124,6 @@ impl CachedLspAdapter { pub async fn new(adapter: Arc) -> Arc { let name = adapter.name().await; let short_name = adapter.short_name(); - let initialization_options = adapter.initialization_options().await; let disk_based_diagnostic_sources = adapter.disk_based_diagnostic_sources().await; let disk_based_diagnostics_progress_token = adapter.disk_based_diagnostics_progress_token().await; @@ -134,7 +132,6 @@ impl CachedLspAdapter { Arc::new(CachedLspAdapter { name, short_name, - initialization_options, disk_based_diagnostic_sources, disk_based_diagnostics_progress_token, language_ids, diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index b9c73ae677..a513b3907a 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -2816,15 +2816,6 @@ impl Project { let lsp = project_settings.lsp.get(&adapter.name.0); let override_options = lsp.map(|s| s.initialization_options.clone()).flatten(); - let mut initialization_options = adapter.initialization_options.clone(); - match (&mut initialization_options, override_options) { - (Some(initialization_options), Some(override_options)) => { - merge_json_value_into(override_options, initialization_options); - } - (None, override_options) => initialization_options = override_options, - _ => {} - } - let server_id = pending_server.server_id; let container_dir = pending_server.container_dir.clone(); let state = LanguageServerState::Starting({ @@ -2837,7 +2828,7 @@ impl Project { let result = Self::setup_and_insert_language_server( this.clone(), &worktree_path, - initialization_options, + override_options, pending_server, adapter.clone(), language.clone(), @@ -2958,7 +2949,7 @@ impl Project { async fn setup_and_insert_language_server( this: WeakModel, worktree_path: &Path, - initialization_options: Option, + override_initialization_options: Option, pending_server: PendingLanguageServer, adapter: Arc, language: Arc, @@ -2968,7 +2959,7 @@ impl Project { ) -> Result>> { let language_server = Self::setup_pending_language_server( this.clone(), - initialization_options, + override_initialization_options, pending_server, worktree_path, adapter.clone(), @@ -2998,7 +2989,7 @@ impl Project { async fn setup_pending_language_server( this: WeakModel, - initialization_options: Option, + override_options: Option, pending_server: PendingLanguageServer, worktree_path: &Path, adapter: Arc, @@ -3164,7 +3155,14 @@ impl Project { } }) .detach(); - + let mut initialization_options = adapter.adapter.initialization_options().await; + match (&mut initialization_options, override_options) { + (Some(initialization_options), Some(override_options)) => { + merge_json_value_into(override_options, initialization_options); + } + (None, override_options) => initialization_options = override_options, + _ => {} + } let language_server = language_server.initialize(initialization_options).await?; language_server From e4aa7ba4f262eb794b798107efbae04fbecb2d87 Mon Sep 17 00:00:00 2001 From: Marshall Bowers Date: Thu, 4 Jan 2024 14:10:46 -0500 Subject: [PATCH 08/13] Try to load fallback fonts instead of panicking when a font is not found (#3891) This PR adjusts our font resolution code to attempt to use a fallback font if the specified font cannot be found. Right now our fallback font stack is `Zed Mono`, followed by `Helvetica` (in practice we should always be able to resolve `Zed Mono` since we bundle it with the app). In the future we'll want to surface the ability to set the fallback font stack from GPUI consumers, and potentially even support specifying font stacks in the user settings (as opposed to a single font family). Release Notes: - Fixed a panic when trying to load a font that could not be found. --- crates/editor/src/editor.rs | 2 +- crates/editor/src/element.rs | 4 +- crates/gpui/src/text_system.rs | 39 +++++++++++++++++++- crates/terminal_view/src/terminal_element.rs | 2 +- 4 files changed, 41 insertions(+), 6 deletions(-) diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index cf074bad41..b53fda335e 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -9565,7 +9565,7 @@ impl InputHandler for Editor { ) -> Option> { let text_layout_details = self.text_layout_details(cx); let style = &text_layout_details.editor_style; - let font_id = cx.text_system().font_id(&style.text.font()).unwrap(); + let font_id = cx.text_system().resolve_font(&style.text.font()); let font_size = style.text.font_size.to_pixels(cx.rem_size()); let line_height = style.text.line_height_in_pixels(cx.rem_size()); let em_width = cx diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index b1a3e73d6a..76a5d1ec5c 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -1775,7 +1775,7 @@ impl EditorElement { let snapshot = editor.snapshot(cx); let style = self.style.clone(); - let font_id = cx.text_system().font_id(&style.text.font()).unwrap(); + let font_id = cx.text_system().resolve_font(&style.text.font()); let font_size = style.text.font_size.to_pixels(cx.rem_size()); let line_height = style.text.line_height_in_pixels(cx.rem_size()); let em_width = cx @@ -3782,7 +3782,7 @@ fn compute_auto_height_layout( } let style = editor.style.as_ref().unwrap(); - let font_id = cx.text_system().font_id(&style.text.font()).unwrap(); + let font_id = cx.text_system().resolve_font(&style.text.font()); let font_size = style.text.font_size.to_pixels(cx.rem_size()); let line_height = style.text.line_height_in_pixels(cx.rem_size()); let em_width = cx diff --git a/crates/gpui/src/text_system.rs b/crates/gpui/src/text_system.rs index 944a9b78be..60934b3959 100644 --- a/crates/gpui/src/text_system.rs +++ b/crates/gpui/src/text_system.rs @@ -15,8 +15,9 @@ use crate::{ use anyhow::anyhow; use collections::FxHashMap; use core::fmt; +use itertools::Itertools; use parking_lot::{Mutex, RwLock, RwLockUpgradableReadGuard}; -use smallvec::SmallVec; +use smallvec::{smallvec, SmallVec}; use std::{ cmp, fmt::{Debug, Display, Formatter}, @@ -42,6 +43,7 @@ pub struct TextSystem { raster_bounds: RwLock>>, wrapper_pool: Mutex>>, font_runs_pool: Mutex>>, + fallback_font_stack: SmallVec<[Font; 2]>, } impl TextSystem { @@ -54,6 +56,12 @@ impl TextSystem { font_ids_by_font: RwLock::default(), wrapper_pool: Mutex::default(), font_runs_pool: Mutex::default(), + fallback_font_stack: smallvec![ + // TODO: This is currently Zed-specific. + // We should allow GPUI users to provide their own fallback font stack. + font("Zed Mono"), + font("Helvetica") + ], } } @@ -72,6 +80,33 @@ impl TextSystem { } } + /// Resolves the specified font, falling back to the default font stack if + /// the font fails to load. + /// + /// # Panics + /// + /// Panics if the font and none of the fallbacks can be resolved. + pub fn resolve_font(&self, font: &Font) -> FontId { + if let Ok(font_id) = self.font_id(font) { + return font_id; + } + + for fallback in &self.fallback_font_stack { + if let Ok(font_id) = self.font_id(fallback) { + return font_id; + } + } + + panic!( + "failed to resolve font '{}' or any of the fallbacks: {}", + font.family, + self.fallback_font_stack + .iter() + .map(|fallback| &fallback.family) + .join(", ") + ); + } + pub fn bounding_box(&self, font_id: FontId, font_size: Pixels) -> Bounds { self.read_metrics(font_id, |metrics| metrics.bounding_box(font_size)) } @@ -159,7 +194,7 @@ impl TextSystem { ) -> Result> { let mut font_runs = self.font_runs_pool.lock().pop().unwrap_or_default(); for run in runs.iter() { - let font_id = self.font_id(&run.font)?; + let font_id = self.resolve_font(&run.font); if let Some(last_run) = font_runs.last_mut() { if last_run.font_id == font_id { last_run.len += run.len; diff --git a/crates/terminal_view/src/terminal_element.rs b/crates/terminal_view/src/terminal_element.rs index 8be10f9469..328a6a1c4e 100644 --- a/crates/terminal_view/src/terminal_element.rs +++ b/crates/terminal_view/src/terminal_element.rs @@ -421,7 +421,7 @@ impl TerminalElement { let rem_size = cx.rem_size(); let font_pixels = text_style.font_size.to_pixels(rem_size); let line_height = font_pixels * line_height.to_pixels(rem_size); - let font_id = cx.text_system().font_id(&text_style.font()).unwrap(); + let font_id = cx.text_system().resolve_font(&text_style.font()); // todo!(do we need to keep this unwrap?) let cell_width = text_system From 2da314fb79aa098b6053d7309435a69099b06008 Mon Sep 17 00:00:00 2001 From: Marshall Bowers Date: Thu, 4 Jan 2024 14:26:08 -0500 Subject: [PATCH 09/13] Fix font resolution for UI text so we render with the fallback font (#3893) This PR updates the font resolution for shaped text to use the new `resolve_font` method on the text system. This makes it so we use the fallback font if the desired font cannot be found rather than rendering nothing. Release Notes: - Fixed an issue where nothing would render when the font set in `ui_font_family` was not found. --- crates/gpui/src/text_system.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/gpui/src/text_system.rs b/crates/gpui/src/text_system.rs index 60934b3959..3106a5a961 100644 --- a/crates/gpui/src/text_system.rs +++ b/crates/gpui/src/text_system.rs @@ -288,7 +288,7 @@ impl TextSystem { last_font = Some(run.font.clone()); font_runs.push(FontRun { len: run_len_within_line, - font_id: self.platform_text_system.font_id(&run.font)?, + font_id: self.resolve_font(&run.font), }); } From 5e3d4885bff7dbebd683a565899983d0b39a393f Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Thu, 4 Jan 2024 13:04:17 -0800 Subject: [PATCH 10/13] Fix some bugs in keymap handling (#3895) - `base_keymap` setting was not respected, now it is - without a `~/.config/zed/keymap.json` file, we would fail to load the *default* keymap Co-authored-by: Marshall --- crates/command_palette/src/command_palette.rs | 16 ++++- crates/gpui/src/app.rs | 16 +++-- crates/settings/src/settings_file.rs | 14 +--- crates/zed/src/zed.rs | 66 ++++++++++++------- 4 files changed, 71 insertions(+), 41 deletions(-) diff --git a/crates/command_palette/src/command_palette.rs b/crates/command_palette/src/command_palette.rs index b7a1dbfd3d..bbc2cd4123 100644 --- a/crates/command_palette/src/command_palette.rs +++ b/crates/command_palette/src/command_palette.rs @@ -370,6 +370,7 @@ mod tests { use gpui::TestAppContext; use language::Point; use project::Project; + use settings::KeymapFile; use workspace::{AppState, Workspace}; #[test] @@ -503,7 +504,20 @@ mod tests { workspace::init(app_state.clone(), cx); init(cx); Project::init_settings(cx); - settings::load_default_keymap(cx); + KeymapFile::parse( + r#"[ + { + "bindings": { + "cmd-n": "workspace::NewFile", + "enter": "menu::Confirm", + "cmd-shift-p": "command_palette::Toggle" + } + } + ]"#, + ) + .unwrap() + .add_to_cx(cx) + .unwrap(); app_state }) } diff --git a/crates/gpui/src/app.rs b/crates/gpui/src/app.rs index f8da622b53..4ad9540043 100644 --- a/crates/gpui/src/app.rs +++ b/crates/gpui/src/app.rs @@ -327,6 +327,7 @@ impl AppContext { pub fn refresh(&mut self) { self.pending_effects.push_back(Effect::Refresh); } + pub(crate) fn update(&mut self, update: impl FnOnce(&mut Self) -> R) -> R { self.pending_updates += 1; let result = update(self); @@ -840,10 +841,12 @@ impl AppContext { /// Update the global of the given type with a closure. Unlike `global_mut`, this method provides /// your closure with mutable access to the `AppContext` and the global simultaneously. pub fn update_global(&mut self, f: impl FnOnce(&mut G, &mut Self) -> R) -> R { - let mut global = self.lease_global::(); - let result = f(&mut global, self); - self.end_global_lease(global); - result + self.update(|cx| { + let mut global = cx.lease_global::(); + let result = f(&mut global, cx); + cx.end_global_lease(global); + result + }) } /// Register a callback to be invoked when a global of the given type is updated. @@ -941,6 +944,11 @@ impl AppContext { self.pending_effects.push_back(Effect::Refresh); } + pub fn clear_key_bindings(&mut self) { + self.keymap.lock().clear(); + self.pending_effects.push_back(Effect::Refresh); + } + /// Register a global listener for actions invoked via the keyboard. pub fn on_action(&mut self, listener: impl Fn(&A, &mut Self) + 'static) { self.global_action_listeners diff --git a/crates/settings/src/settings_file.rs b/crates/settings/src/settings_file.rs index 590079c51b..3a43e3f9dd 100644 --- a/crates/settings/src/settings_file.rs +++ b/crates/settings/src/settings_file.rs @@ -1,4 +1,4 @@ -use crate::{settings_store::SettingsStore, KeymapFile, Settings}; +use crate::{settings_store::SettingsStore, Settings}; use anyhow::Result; use fs::Fs; use futures::{channel::mpsc, StreamExt}; @@ -77,7 +77,6 @@ pub fn handle_settings_file_changes( }); cx.spawn(move |mut cx| async move { while let Some(user_settings_content) = user_settings_file_rx.next().await { - eprintln!("settings file changed"); let result = cx.update_global(|store: &mut SettingsStore, cx| { store .set_user_settings(&user_settings_content, cx) @@ -121,14 +120,3 @@ pub fn update_settings_file( }) .detach_and_log_err(cx); } - -pub fn load_default_keymap(cx: &mut AppContext) { - for path in ["keymaps/default.json", "keymaps/vim.json"] { - KeymapFile::load_asset(path, cx).unwrap(); - } - - // todo!() - // if let Some(asset_path) = settings::get::(cx).asset_path() { - // KeymapFile::load_asset(asset_path, cx).unwrap(); - // } -} diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index fb85b1fc01..fea84c2964 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -18,11 +18,11 @@ pub use only_instance::*; pub use open_listener::*; use anyhow::{anyhow, Context as _}; -use futures::{channel::mpsc, StreamExt}; +use futures::{channel::mpsc, select_biased, StreamExt}; use project_panel::ProjectPanel; use quick_action_bar::QuickActionBar; use search::project_search::ProjectSearchBar; -use settings::{initial_local_settings_content, load_default_keymap, KeymapFile, Settings}; +use settings::{initial_local_settings_content, KeymapFile, Settings, SettingsStore}; use std::{borrow::Cow, ops::Deref, sync::Arc}; use terminal_view::terminal_panel::TerminalPanel; use util::{ @@ -32,6 +32,7 @@ use util::{ ResultExt, }; use uuid::Uuid; +use welcome::BaseKeymap; use workspace::Pane; use workspace::{ create_and_open_local_file, notifications::simple_message_notification::MessageNotification, @@ -399,8 +400,7 @@ pub fn initialize_workspace(app_state: Arc, cx: &mut AppContext) { }); workspace.focus_handle(cx).focus(cx); - //todo!() - // load_default_keymap(cx); + load_default_keymap(cx); }) .detach(); } @@ -558,38 +558,58 @@ pub fn handle_keymap_file_changes( mut user_keymap_file_rx: mpsc::UnboundedReceiver, cx: &mut AppContext, ) { - cx.spawn(move |cx| async move { - // let mut settings_subscription = None; - while let Some(user_keymap_content) = user_keymap_file_rx.next().await { - if let Some(keymap_content) = KeymapFile::parse(&user_keymap_content).log_err() { - cx.update(|cx| reload_keymaps(cx, &keymap_content)).ok(); + BaseKeymap::register(cx); - // todo!() - // let mut old_base_keymap = cx.read(|cx| *settings::get::(cx)); - // drop(settings_subscription); - // settings_subscription = Some(cx.update(|cx| { - // cx.observe_global::(move |cx| { - // let new_base_keymap = *settings::get::(cx); - // if new_base_keymap != old_base_keymap { - // old_base_keymap = new_base_keymap.clone(); - // reload_keymaps(cx, &keymap_content); - // } - // }) - // })); + let (base_keymap_tx, mut base_keymap_rx) = mpsc::unbounded(); + let mut old_base_keymap = *BaseKeymap::get_global(cx); + cx.observe_global::(move |cx| { + let new_base_keymap = *BaseKeymap::get_global(cx); + if new_base_keymap != old_base_keymap { + old_base_keymap = new_base_keymap.clone(); + base_keymap_tx.unbounded_send(()).unwrap(); + } + }) + .detach(); + + cx.spawn(move |cx| async move { + let mut user_keymap = KeymapFile::default(); + loop { + select_biased! { + _ = base_keymap_rx.next() => {} + user_keymap_content = user_keymap_file_rx.next() => { + if let Some(user_keymap_content) = user_keymap_content { + if let Some(keymap_content) = KeymapFile::parse(&user_keymap_content).log_err() { + user_keymap = keymap_content; + } else { + continue + } + } + } } + + cx.update(|cx| reload_keymaps(cx, &user_keymap)).ok(); } }) .detach(); } fn reload_keymaps(cx: &mut AppContext, keymap_content: &KeymapFile) { - // todo!() - // cx.clear_bindings(); + cx.clear_key_bindings(); load_default_keymap(cx); keymap_content.clone().add_to_cx(cx).log_err(); cx.set_menus(app_menus()); } +pub fn load_default_keymap(cx: &mut AppContext) { + for path in ["keymaps/default.json", "keymaps/vim.json"] { + KeymapFile::load_asset(path, cx).unwrap(); + } + + if let Some(asset_path) = BaseKeymap::get_global(cx).asset_path() { + KeymapFile::load_asset(asset_path, cx).unwrap(); + } +} + fn open_local_settings_file( workspace: &mut Workspace, _: &OpenLocalSettings, From 32cd4d778a43c1b697da4a9f6d796a606a6ae169 Mon Sep 17 00:00:00 2001 From: Marshall Bowers Date: Thu, 4 Jan 2024 17:10:08 -0500 Subject: [PATCH 11/13] Render an empty placeholder when not showing file icons in the project panel (#3897) This PR makes it so when we're not showing file icons in the project panel we render an empty placeholder instead of nothing. This prevents the indentation of the items in the file tree from changing based on the presence of the icon. Release Notes: - Fixed layout shift when `project_panel.file_icons` is set to `false`. --- crates/project_panel/src/project_panel.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/project_panel/src/project_panel.rs b/crates/project_panel/src/project_panel.rs index e0bee14df2..6662014c46 100644 --- a/crates/project_panel/src/project_panel.rs +++ b/crates/project_panel/src/project_panel.rs @@ -1395,7 +1395,7 @@ impl ProjectPanel { .child(if let Some(icon) = &icon { div().child(IconElement::from_path(icon.to_string()).color(Color::Muted)) } else { - div() + div().size(IconSize::default().rems()).invisible() }) .child( if let (Some(editor), true) = (Some(&self.filename_editor), show_editor) { From 47476faef1e0121f66791f8e0aad906e1f263273 Mon Sep 17 00:00:00 2001 From: Marshall Bowers Date: Thu, 4 Jan 2024 17:25:11 -0500 Subject: [PATCH 12/13] Fix label color for inactive tabs (#3899) This PR fixes an issue where certain tabs were not using the correct color for their labels when they were inactive. Release Notes: - Fixed an issue where some inactive tabs were not using the correct label color. --- crates/diagnostics/src/diagnostics.rs | 9 +++++++-- crates/language_tools/src/lsp_log.rs | 12 +++++++++--- crates/language_tools/src/syntax_tree_view.rs | 10 ++++++++-- 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/crates/diagnostics/src/diagnostics.rs b/crates/diagnostics/src/diagnostics.rs index 77e6a7673f..9d5a62cff1 100644 --- a/crates/diagnostics/src/diagnostics.rs +++ b/crates/diagnostics/src/diagnostics.rs @@ -641,8 +641,13 @@ impl Item for ProjectDiagnosticsEditor { fn tab_content(&self, _detail: Option, selected: bool, _: &WindowContext) -> AnyElement { if self.summary.error_count == 0 && self.summary.warning_count == 0 { - let label = Label::new("No problems"); - label.into_any_element() + Label::new("No problems") + .color(if selected { + Color::Default + } else { + Color::Muted + }) + .into_any_element() } else { h_stack() .gap_1() diff --git a/crates/language_tools/src/lsp_log.rs b/crates/language_tools/src/lsp_log.rs index e38de7d373..123149eae2 100644 --- a/crates/language_tools/src/lsp_log.rs +++ b/crates/language_tools/src/lsp_log.rs @@ -10,7 +10,7 @@ use language::{LanguageServerId, LanguageServerName}; use lsp::IoKind; use project::{search::SearchQuery, Project}; use std::{borrow::Cow, sync::Arc}; -use ui::{h_stack, popover_menu, Button, Checkbox, Clickable, ContextMenu, Label, Selection}; +use ui::{popover_menu, prelude::*, Button, Checkbox, ContextMenu, Label, Selection}; use workspace::{ item::{Item, ItemHandle}, searchable::{SearchEvent, SearchableItem, SearchableItemHandle}, @@ -614,8 +614,14 @@ impl Item for LspLogView { Editor::to_item_events(event, f) } - fn tab_content(&self, _: Option, _: bool, _: &WindowContext<'_>) -> AnyElement { - Label::new("LSP Logs").into_any_element() + fn tab_content(&self, _: Option, selected: bool, _: &WindowContext<'_>) -> AnyElement { + Label::new("LSP Logs") + .color(if selected { + Color::Default + } else { + Color::Muted + }) + .into_any_element() } fn as_searchable(&self, handle: &View) -> Option> { diff --git a/crates/language_tools/src/syntax_tree_view.rs b/crates/language_tools/src/syntax_tree_view.rs index a36264261e..c30564e9bf 100644 --- a/crates/language_tools/src/syntax_tree_view.rs +++ b/crates/language_tools/src/syntax_tree_view.rs @@ -405,8 +405,14 @@ impl Item for SyntaxTreeView { fn to_item_events(_: &Self::Event, _: impl FnMut(workspace::item::ItemEvent)) {} - fn tab_content(&self, _: Option, _: bool, _: &WindowContext<'_>) -> AnyElement { - Label::new("Syntax Tree").into_any_element() + fn tab_content(&self, _: Option, selected: bool, _: &WindowContext<'_>) -> AnyElement { + Label::new("Syntax Tree") + .color(if selected { + Color::Default + } else { + Color::Muted + }) + .into_any_element() } fn clone_on_split( From a8efb41e56dc7ae412e948aa3599cbe4bc9f97f2 Mon Sep 17 00:00:00 2001 From: "Joseph T. Lyons" Date: Thu, 4 Jan 2024 17:28:07 -0500 Subject: [PATCH 13/13] Remove outdated TODOs --- crates/zed/src/app_menus.rs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/crates/zed/src/app_menus.rs b/crates/zed/src/app_menus.rs index a4b0e21d6e..2aff05d884 100644 --- a/crates/zed/src/app_menus.rs +++ b/crates/zed/src/app_menus.rs @@ -150,14 +150,6 @@ pub fn app_menus() -> Vec> { MenuItem::action("View Dependency Licenses", crate::OpenLicenses), MenuItem::action("Show Welcome", workspace::Welcome), MenuItem::separator(), - // todo!(): Needs `feedback` crate. - // MenuItem::action("Give us feedback", feedback::feedback_editor::GiveFeedback), - // MenuItem::action( - // "Copy System Specs Into Clipboard", - // feedback::CopySystemSpecsIntoClipboard, - // ), - // MenuItem::action("File Bug Report", feedback::FileBugReport), - // MenuItem::action("Request Feature", feedback::RequestFeature), MenuItem::separator(), MenuItem::action( "Documentation",