From a7550de8c57c4ee143ed696de3362314f0c3b305 Mon Sep 17 00:00:00 2001 From: Julia Date: Wed, 3 Jan 2024 14:36:10 -0500 Subject: [PATCH 1/8] 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 9bafb0c0bba7c8219c729b5b3e15830355710fdf..351c851bb9088db8907e7defff71fe21d79ffe75 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 2/8] 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 ab29f6c8b290de894b4528c50dd5f20bf5d748bf..b1a3e73d6a6372c99551a409edc630331727523c 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 3/8] 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 1d0af3c00876104d2f8554ee43ed757689bce281..13d4be62337ae0557fbc59538db4a4bdceacd22e 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 6f438098b718a72602e69b81339129e00fa8a3ba..e0bee14df27479021634d3400b13850d44fa51a9 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 4/8] 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 691b83479f1e4fb793068aca9d4f2af55124413a..a2a90d4f2f69c94fc87a56ff13d8aa861304699b 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 5/8] 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 5564481c6bdc07a41d0b3fdd91a75970de9b8e21..366d2b0098ca36437252044c50825bceaed96081 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 b9c73ae67785d48d7912414113329bb4a6d2e0da..a513b3907adcee142db6c09b481c99ae03384b6d 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 6/8] 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 cf074bad415d499516c1bb693cbfc19c4482f41c..b53fda335ed55ad1d31885cbe227d9c9cf339c28 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 b1a3e73d6a6372c99551a409edc630331727523c..76a5d1ec5ce9131dfaeeba46c73e95e5181003e2 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 944a9b78bec2a33b4b20e4e1e1b991565d42212b..60934b3959722eb76f9a86a16b6669d06109dd74 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 8be10f9469fd8a2fb716f469c39bae841500920e..328a6a1c4e8cd37dcc698ada592a60e7c9767628 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 7/8] 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 60934b3959722eb76f9a86a16b6669d06109dd74..3106a5a961514157d2daf4d0360c395fae45c2df 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 8/8] 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 b7a1dbfd3dd48abc08a05e6a151a24fa3ef4af83..bbc2cd412305aff870f712187c4b7e13d916303d 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 f8da622b53bcc1beb4e1e33c3f3cd860696801b7..4ad9540043e1058ee9ab9f5e9df9ef9bbce92057 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 590079c51b52fe77a2c83ec4a862b27a0202ad1a..3a43e3f9dd6a22a5c6e8d74dece4a7982231af4e 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 fb85b1fc012085720dd7e11c1863cefcae84723a..fea84c296419c2a7f41a538ec026cdececeee99f 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, ) { + BaseKeymap::register(cx); + + let (base_keymap_tx, mut base_keymap_rx) = mpsc::unbounded(); + let mut old_base_keymap = *BaseKeymap::get_global(cx); + cx.observe_global::(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 settings_subscription = None; - while let Some(user_keymap_content) = user_keymap_file_rx.next().await { - if let Some(keymap_content) = KeymapFile::parse(&user_keymap_content).log_err() { - cx.update(|cx| reload_keymaps(cx, &keymap_content)).ok(); - - // todo!() - // let mut old_base_keymap = cx.read(|cx| *settings::get::(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 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,