From 814e62050c89d340fe63a2e2033b1c455d7a97b3 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Tue, 7 Nov 2023 20:58:37 -0700 Subject: [PATCH] Register actions globally before main --- crates/client2/src/client2.rs | 3 - crates/editor2/src/editor.rs | 124 --------------------- crates/gpui2/src/action.rs | 30 ++++- crates/gpui2/src/app.rs | 31 +----- crates/gpui2_macros/src/register_action.rs | 6 +- crates/settings2/src/keymap_file.rs | 4 +- crates/storybook2/src/stories/focus.rs | 2 - crates/zed2/src/languages/json.rs | 2 +- 8 files changed, 33 insertions(+), 169 deletions(-) diff --git a/crates/client2/src/client2.rs b/crates/client2/src/client2.rs index 4a1c5f321c375a097a89252830bd17c572d0c648..93ec7f329bfab51f11d3689904cbc4d5edb62071 100644 --- a/crates/client2/src/client2.rs +++ b/crates/client2/src/client2.rs @@ -80,7 +80,6 @@ pub fn init(client: &Arc, cx: &mut AppContext) { init_settings(cx); let client = Arc::downgrade(client); - cx.register_action_type::(); cx.on_action({ let client = client.clone(); move |_: &SignIn, cx| { @@ -93,7 +92,6 @@ pub fn init(client: &Arc, cx: &mut AppContext) { } }); - cx.register_action_type::(); cx.on_action({ let client = client.clone(); move |_: &SignOut, cx| { @@ -106,7 +104,6 @@ pub fn init(client: &Arc, cx: &mut AppContext) { } }); - cx.register_action_type::(); cx.on_action({ let client = client.clone(); move |_: &Reconnect, cx| { diff --git a/crates/editor2/src/editor.rs b/crates/editor2/src/editor.rs index 13afe8aebac141f9d202ab363cdae0ed0cb62f79..e7936b8ebc226a569775df417362f03818964753 100644 --- a/crates/editor2/src/editor.rs +++ b/crates/editor2/src/editor.rs @@ -406,130 +406,6 @@ pub fn init_settings(cx: &mut AppContext) { pub fn init(cx: &mut AppContext) { init_settings(cx); - // cx.register_action_type(Editor::new_file); - // cx.register_action_type(Editor::new_file_in_direction); - // cx.register_action_type(Editor::cancel); - // cx.register_action_type(Editor::newline); - // cx.register_action_type(Editor::newline_above); - // cx.register_action_type(Editor::newline_below); - // cx.register_action_type(Editor::backspace); - // cx.register_action_type(Editor::delete); - // cx.register_action_type(Editor::tab); - // cx.register_action_type(Editor::tab_prev); - // cx.register_action_type(Editor::indent); - // cx.register_action_type(Editor::outdent); - // cx.register_action_type(Editor::delete_line); - // cx.register_action_type(Editor::join_lines); - // cx.register_action_type(Editor::sort_lines_case_sensitive); - // cx.register_action_type(Editor::sort_lines_case_insensitive); - // cx.register_action_type(Editor::reverse_lines); - // cx.register_action_type(Editor::shuffle_lines); - // cx.register_action_type(Editor::convert_to_upper_case); - // cx.register_action_type(Editor::convert_to_lower_case); - // cx.register_action_type(Editor::convert_to_title_case); - // cx.register_action_type(Editor::convert_to_snake_case); - // cx.register_action_type(Editor::convert_to_kebab_case); - // cx.register_action_type(Editor::convert_to_upper_camel_case); - // cx.register_action_type(Editor::convert_to_lower_camel_case); - // cx.register_action_type(Editor::delete_to_previous_word_start); - // cx.register_action_type(Editor::delete_to_previous_subword_start); - // cx.register_action_type(Editor::delete_to_next_word_end); - // cx.register_action_type(Editor::delete_to_next_subword_end); - // cx.register_action_type(Editor::delete_to_beginning_of_line); - // cx.register_action_type(Editor::delete_to_end_of_line); - // cx.register_action_type(Editor::cut_to_end_of_line); - // cx.register_action_type(Editor::duplicate_line); - // cx.register_action_type(Editor::move_line_up); - // cx.register_action_type(Editor::move_line_down); - // cx.register_action_type(Editor::transpose); - // cx.register_action_type(Editor::cut); - // cx.register_action_type(Editor::copy); - // cx.register_action_type(Editor::paste); - // cx.register_action_type(Editor::undo); - // cx.register_action_type(Editor::redo); - cx.register_action_type::(); - // cx.register_action_type(Editor::move_page_up); - cx.register_action_type::(); - // cx.register_action_type(Editor::move_page_down); - // cx.register_action_type(Editor::next_screen); - cx.register_action_type::(); - cx.register_action_type::(); - // cx.register_action_type(Editor::move_to_previous_word_start); - // cx.register_action_type(Editor::move_to_previous_subword_start); - // cx.register_action_type(Editor::move_to_next_word_end); - // cx.register_action_type(Editor::move_to_next_subword_end); - // cx.register_action_type(Editor::move_to_beginning_of_line); - // cx.register_action_type(Editor::move_to_end_of_line); - // cx.register_action_type(Editor::move_to_start_of_paragraph); - // cx.register_action_type(Editor::move_to_end_of_paragraph); - // cx.register_action_type(Editor::move_to_beginning); - // cx.register_action_type(Editor::move_to_end); - // cx.register_action_type(Editor::select_up); - // cx.register_action_type(Editor::select_down); - // cx.register_action_type(Editor::select_left); - // cx.register_action_type(Editor::select_right); - // cx.register_action_type(Editor::select_to_previous_word_start); - // cx.register_action_type(Editor::select_to_previous_subword_start); - // cx.register_action_type(Editor::select_to_next_word_end); - // cx.register_action_type(Editor::select_to_next_subword_end); - // cx.register_action_type(Editor::select_to_beginning_of_line); - // cx.register_action_type(Editor::select_to_end_of_line); - // cx.register_action_type(Editor::select_to_start_of_paragraph); - // cx.register_action_type(Editor::select_to_end_of_paragraph); - // cx.register_action_type(Editor::select_to_beginning); - // cx.register_action_type(Editor::select_to_end); - // cx.register_action_type(Editor::select_all); - // cx.register_action_type(Editor::select_all_matches); - // cx.register_action_type(Editor::select_line); - // cx.register_action_type(Editor::split_selection_into_lines); - // cx.register_action_type(Editor::add_selection_above); - // cx.register_action_type(Editor::add_selection_below); - // cx.register_action_type(Editor::select_next); - // cx.register_action_type(Editor::select_previous); - // cx.register_action_type(Editor::toggle_comments); - // cx.register_action_type(Editor::select_larger_syntax_node); - // cx.register_action_type(Editor::select_smaller_syntax_node); - // cx.register_action_type(Editor::move_to_enclosing_bracket); - // cx.register_action_type(Editor::undo_selection); - // cx.register_action_type(Editor::redo_selection); - // cx.register_action_type(Editor::go_to_diagnostic); - // cx.register_action_type(Editor::go_to_prev_diagnostic); - // cx.register_action_type(Editor::go_to_hunk); - // cx.register_action_type(Editor::go_to_prev_hunk); - // cx.register_action_type(Editor::go_to_definition); - // cx.register_action_type(Editor::go_to_definition_split); - // cx.register_action_type(Editor::go_to_type_definition); - // cx.register_action_type(Editor::go_to_type_definition_split); - // cx.register_action_type(Editor::fold); - // cx.register_action_type(Editor::fold_at); - // cx.register_action_type(Editor::unfold_lines); - // cx.register_action_type(Editor::unfold_at); - // cx.register_action_type(Editor::gutter_hover); - // cx.register_action_type(Editor::fold_selected_ranges); - // cx.register_action_type(Editor::show_completions); - // cx.register_action_type(Editor::toggle_code_actions); - // cx.register_action_type(Editor::open_excerpts); - // cx.register_action_type(Editor::toggle_soft_wrap); - // cx.register_action_type(Editor::toggle_inlay_hints); - // cx.register_action_type(Editor::reveal_in_finder); - // cx.register_action_type(Editor::copy_path); - // cx.register_action_type(Editor::copy_relative_path); - // cx.register_action_type(Editor::copy_highlight_json); - // cx.add_async_action(Editor::format); - // cx.register_action_type(Editor::restart_language_server); - // cx.register_action_type(Editor::show_character_palette); - // cx.add_async_action(Editor::confirm_completion); - // cx.add_async_action(Editor::confirm_code_action); - // cx.add_async_action(Editor::rename); - // cx.add_async_action(Editor::confirm_rename); - // cx.add_async_action(Editor::find_all_references); - // cx.register_action_type(Editor::next_copilot_suggestion); - // cx.register_action_type(Editor::previous_copilot_suggestion); - // cx.register_action_type(Editor::copilot_suggest); - // cx.register_action_type(Editor::context_menu_first); - // cx.register_action_type(Editor::context_menu_prev); - // cx.register_action_type(Editor::context_menu_next); - // cx.register_action_type(Editor::context_menu_last); hover_popover::init(cx); scroll::actions::init(cx); diff --git a/crates/gpui2/src/action.rs b/crates/gpui2/src/action.rs index 289d858c62a8d246fba18561f606dcf36ec26eac..ba4ed077f22f7aa1e17e8ca66359fafe32fb57a3 100644 --- a/crates/gpui2/src/action.rs +++ b/crates/gpui2/src/action.rs @@ -1,8 +1,8 @@ use crate::SharedString; use anyhow::{anyhow, Context, Result}; use collections::{HashMap, HashSet}; -use ctor::ctor; -use parking_lot::Mutex; +use lazy_static::lazy_static; +use parking_lot::{MappedRwLockReadGuard, RwLock, RwLockReadGuard}; use serde::Deserialize; use std::any::{type_name, Any}; @@ -21,23 +21,41 @@ pub trait Action: std::fmt::Debug + 'static { type ActionBuilder = fn(json: Option) -> anyhow::Result>; -#[ctor] -static ACTION_BUILDERS: Mutex> = Mutex::default(); +lazy_static! { + static ref ACTION_REGISTRY: RwLock = RwLock::default(); +} + +#[derive(Default)] +struct ActionRegistry { + builders_by_name: HashMap, + all_names: Vec, // So we can return a static slice. +} /// Register an action type to allow it to be referenced in keymaps. pub fn register_action() { - ACTION_BUILDERS.lock().insert(A::qualified_name(), A::build); + let name = A::qualified_name(); + let mut lock = ACTION_REGISTRY.write(); + lock.builders_by_name.insert(name.clone(), A::build); + lock.all_names.push(name); } /// Construct an action based on its name and optional JSON parameters sourced from the keymap. pub fn build_action(name: &str, params: Option) -> Result> { - let lock = &ACTION_BUILDERS.lock(); + let lock = ACTION_REGISTRY.read(); let build_action = lock + .builders_by_name .get(name) .ok_or_else(|| anyhow!("no action type registered for {}", name))?; (build_action)(params) } +pub fn all_action_names() -> MappedRwLockReadGuard<'static, [SharedString]> { + let lock = ACTION_REGISTRY.read(); + RwLockReadGuard::map(lock, |registry: &ActionRegistry| { + registry.all_names.as_slice() + }) +} + // actions defines structs that can be used as actions. #[macro_export] macro_rules! actions { diff --git a/crates/gpui2/src/app.rs b/crates/gpui2/src/app.rs index 63d2143a6726773be7508c77c72bdd6b1052fe3d..0267f4723686bcf5c60e52da09e079f5ac7393b5 100644 --- a/crates/gpui2/src/app.rs +++ b/crates/gpui2/src/app.rs @@ -17,9 +17,9 @@ use crate::{ current_platform, image_cache::ImageCache, Action, AnyBox, AnyView, AnyWindowHandle, AppMetadata, AssetSource, BackgroundExecutor, ClipboardItem, Context, DispatchPhase, DisplayId, Entity, FocusEvent, FocusHandle, FocusId, ForegroundExecutor, KeyBinding, Keymap, LayoutId, - PathPromptOptions, Pixels, Platform, PlatformDisplay, Point, Render, SharedString, - SubscriberSet, Subscription, SvgRenderer, Task, TextStyle, TextStyleRefinement, TextSystem, - View, Window, WindowContext, WindowHandle, WindowId, + PathPromptOptions, Pixels, Platform, PlatformDisplay, Point, Render, SubscriberSet, + Subscription, SvgRenderer, Task, TextStyle, TextStyleRefinement, TextSystem, View, Window, + WindowContext, WindowHandle, WindowId, }; use anyhow::{anyhow, Result}; use collections::{HashMap, HashSet, VecDeque}; @@ -140,7 +140,6 @@ impl App { } } -type ActionBuilder = fn(json: Option) -> anyhow::Result>; pub(crate) type FrameCallback = Box; type Handler = Box bool + 'static>; type Listener = Box bool + 'static>; @@ -176,7 +175,6 @@ pub struct AppContext { pub(crate) keymap: Arc>, pub(crate) global_action_listeners: HashMap>>, - action_builders: HashMap, pending_effects: VecDeque, pub(crate) pending_notifications: HashSet, pub(crate) pending_global_notifications: HashSet, @@ -234,7 +232,6 @@ impl AppContext { windows: SlotMap::with_key(), keymap: Arc::new(Mutex::new(Keymap::default())), global_action_listeners: HashMap::default(), - action_builders: HashMap::default(), pending_effects: VecDeque::new(), pending_notifications: HashSet::default(), pending_global_notifications: HashSet::default(), @@ -695,10 +692,6 @@ impl AppContext { ) } - pub fn all_action_names<'a>(&'a self) -> impl Iterator + 'a { - self.action_builders.keys().cloned() - } - /// Move the global of the given type to the stack. pub(crate) fn lease_global(&mut self) -> GlobalLease { GlobalLease::new( @@ -761,24 +754,6 @@ impl AppContext { })); } - /// Register an action type to allow it to be referenced in keymaps. - pub fn register_action_type(&mut self) { - self.action_builders.insert(A::qualified_name(), A::build); - } - - /// Construct an action based on its name and parameters. - pub fn build_action( - &mut self, - name: &str, - params: Option, - ) -> Result> { - let build = self - .action_builders - .get(name) - .ok_or_else(|| anyhow!("no action type registered for {}", name))?; - (build)(params) - } - /// Event handlers propagate events by default. Call this method to stop dispatching to /// event handlers with a lower z-index (mouse) or higher in the tree (keyboard). This is /// the opposite of [propagate]. It's also possible to cancel a call to [propagate] by diff --git a/crates/gpui2_macros/src/register_action.rs b/crates/gpui2_macros/src/register_action.rs index 77516cdec8278edc28e011800795f17294e5c2ee..ab00daf4773a620200d2edd8129dd666a233bfde 100644 --- a/crates/gpui2_macros/src/register_action.rs +++ b/crates/gpui2_macros/src/register_action.rs @@ -1,14 +1,14 @@ // Input: // -// struct Foo {} +// struct FooBar {} // Output: // -// struct Foo {} +// struct FooBar {} // // #[allow(non_snake_case)] // #[gpui2::ctor] -// fn register_Foo_builder() { +// fn register_foobar_builder() { // gpui2::register_action_builder::() // } use proc_macro::TokenStream; diff --git a/crates/settings2/src/keymap_file.rs b/crates/settings2/src/keymap_file.rs index e51bd76e5e0c9e0d86241a9c3bb816c90d0e1063..ec1f02a95d103a78f05a5f8f028f4ce5cc6b709a 100644 --- a/crates/settings2/src/keymap_file.rs +++ b/crates/settings2/src/keymap_file.rs @@ -73,9 +73,9 @@ impl KeymapFile { "Expected first item in array to be a string." ))); }; - cx.build_action(&name, Some(data)) + gpui::build_action(&name, Some(data)) } - Value::String(name) => cx.build_action(&name, None), + Value::String(name) => gpui::build_action(&name, None), Value::Null => Ok(no_action()), _ => { return Some(Err(anyhow!("Expected two-element array, got {action:?}"))) diff --git a/crates/storybook2/src/stories/focus.rs b/crates/storybook2/src/stories/focus.rs index 0f580d0cbf171ef32b2c83465ad8601785304227..57f9869859710bfd07967af6e8170c8048634124 100644 --- a/crates/storybook2/src/stories/focus.rs +++ b/crates/storybook2/src/stories/focus.rs @@ -15,8 +15,6 @@ impl FocusStory { KeyBinding::new("cmd-a", ActionB, Some("child-1")), KeyBinding::new("cmd-c", ActionC, None), ]); - cx.register_action_type::(); - cx.register_action_type::(); cx.build_view(move |cx| Self {}) } diff --git a/crates/zed2/src/languages/json.rs b/crates/zed2/src/languages/json.rs index 63f909ae2a2e264ea672dee48e305ba1be82e066..cf9b33d9683cadd9f5b27c41104d215becd1110d 100644 --- a/crates/zed2/src/languages/json.rs +++ b/crates/zed2/src/languages/json.rs @@ -107,7 +107,7 @@ impl LspAdapter for JsonLspAdapter { &self, cx: &mut AppContext, ) -> BoxFuture<'static, serde_json::Value> { - let action_names = cx.all_action_names().collect::>(); + let action_names = gpui::all_action_names(); let staff_mode = cx.is_staff(); let language_names = &self.languages.language_names(); let settings_schema = cx.global::().json_schema(