gpui: Add action_schema_by_name for O(1) action schema lookup (#47180)

Xiaobo Liu created

Release Notes:

- N/A


Avoids iterating through all registered actions when looking up a single
action's schema in json_schema_store.

---------

Signed-off-by: Xiaobo Liu <cppcoffee@gmail.com>

Change summary

crates/gpui/src/action.rs                         | 10 ++++++++++
crates/gpui/src/app.rs                            | 12 ++++++++++++
crates/json_schema_store/src/json_schema_store.rs | 11 +++++++++++
3 files changed, 33 insertions(+)

Detailed changes

crates/gpui/src/action.rs 🔗

@@ -397,6 +397,16 @@ impl ActionRegistry {
             .collect::<Vec<_>>()
     }
 
+    pub fn action_schema_by_name(
+        &self,
+        name: &str,
+        generator: &mut schemars::SchemaGenerator,
+    ) -> Option<Option<schemars::Schema>> {
+        self.by_name
+            .get(name)
+            .map(|action_data| (action_data.json_schema)(generator))
+    }
+
     pub fn deprecated_aliases(&self) -> &HashMap<&'static str, &'static str> {
         &self.deprecated_aliases
     }

crates/gpui/src/app.rs 🔗

@@ -1876,6 +1876,18 @@ impl App {
         self.actions.action_schemas(generator)
     }
 
+    /// Get the schema for a specific action by name.
+    /// Returns `None` if the action is not found.
+    /// Returns `Some(None)` if the action exists but has no schema.
+    /// Returns `Some(Some(schema))` if the action exists and has a schema.
+    pub fn action_schema_by_name(
+        &self,
+        name: &str,
+        generator: &mut schemars::SchemaGenerator,
+    ) -> Option<Option<schemars::Schema>> {
+        self.actions.action_schema_by_name(name, generator)
+    }
+
     /// Get a map from a deprecated action name to the canonical name.
     pub fn deprecated_actions_to_preferred_actions(&self) -> &HashMap<&'static str, &'static str> {
         self.actions.deprecated_aliases()

crates/json_schema_store/src/json_schema_store.rs 🔗

@@ -300,6 +300,17 @@ async fn resolve_dynamic_schema(
             });
             task::DebugTaskFile::generate_json_schema(&adapter_schemas)
         }
+        "keymap" => cx.update(settings::KeymapFile::generate_json_schema_for_registered_actions),
+        "action" => {
+            let normalized_action_name = rest.context("No Action name provided")?;
+            let action_name = denormalize_action_name(normalized_action_name);
+            let mut generator = settings::KeymapFile::action_schema_generator();
+            let schema = cx
+                .update(|cx| cx.action_schema_by_name(&action_name, &mut generator))
+                .flatten();
+            root_schema_from_action_schema(schema, &mut generator).to_value()
+        }
+        "tasks" => task::TaskTemplates::generate_json_schema(),
         _ => {
             anyhow::bail!("Unrecognized schema: {schema_name}");
         }