Rename the OpenFile action to OpenSelectedFilename to better reflect its function (#22494)

Release Notes:

- Renamed the `OpenFile` action to `OpenSelectedFilename` for clarity
This commit is contained in:
Cole Miller 2025-01-06 23:18:04 -05:00 committed by GitHub
parent 2ba91609c9
commit 810b37c129
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 113 additions and 33 deletions

View file

@ -1,6 +1,6 @@
//! This module contains all actions supported by [`Editor`]. //! This module contains all actions supported by [`Editor`].
use super::*; use super::*;
use gpui::action_as; use gpui::{action_aliases, action_as};
use util::serde::default_true; use util::serde::default_true;
#[derive(PartialEq, Clone, Deserialize, Default)] #[derive(PartialEq, Clone, Deserialize, Default)]
@ -311,7 +311,6 @@ gpui::actions!(
OpenExcerpts, OpenExcerpts,
OpenExcerptsSplit, OpenExcerptsSplit,
OpenProposedChangesEditor, OpenProposedChangesEditor,
OpenFile,
OpenDocs, OpenDocs,
OpenPermalinkToLine, OpenPermalinkToLine,
OpenUrl, OpenUrl,
@ -389,3 +388,5 @@ gpui::actions!(
); );
action_as!(go_to_line, ToggleGoToLine as Toggle); action_as!(go_to_line, ToggleGoToLine as Toggle);
action_aliases!(editor, OpenSelectedFilename, [OpenFile]);

View file

@ -9503,7 +9503,7 @@ impl Editor {
url_finder.detach(); url_finder.detach();
} }
pub fn open_file(&mut self, _: &OpenFile, cx: &mut ViewContext<Self>) { pub fn open_selected_filename(&mut self, _: &OpenSelectedFilename, cx: &mut ViewContext<Self>) {
let Some(workspace) = self.workspace() else { let Some(workspace) = self.workspace() else {
return; return;
}; };

View file

@ -342,7 +342,7 @@ impl EditorElement {
.detach_and_log_err(cx); .detach_and_log_err(cx);
}); });
register_action(view, cx, Editor::open_url); register_action(view, cx, Editor::open_url);
register_action(view, cx, Editor::open_file); register_action(view, cx, Editor::open_selected_filename);
register_action(view, cx, Editor::fold); register_action(view, cx, Editor::fold);
register_action(view, cx, Editor::fold_at_level); register_action(view, cx, Editor::fold_at_level);
register_action(view, cx, Editor::fold_all); register_action(view, cx, Editor::fold_all);

View file

@ -62,6 +62,14 @@ pub trait Action: 'static + Send {
fn build(value: serde_json::Value) -> Result<Box<dyn Action>> fn build(value: serde_json::Value) -> Result<Box<dyn Action>>
where where
Self: Sized; Self: Sized;
/// A list of alternate, deprecated names for this action.
fn deprecated_aliases() -> &'static [&'static str]
where
Self: Sized,
{
&[]
}
} }
impl std::fmt::Debug for dyn Action { impl std::fmt::Debug for dyn Action {
@ -85,6 +93,7 @@ pub(crate) struct ActionRegistry {
builders_by_name: HashMap<SharedString, ActionBuilder>, builders_by_name: HashMap<SharedString, ActionBuilder>,
names_by_type_id: HashMap<TypeId, SharedString>, names_by_type_id: HashMap<TypeId, SharedString>,
all_names: Vec<SharedString>, // So we can return a static slice. all_names: Vec<SharedString>, // So we can return a static slice.
deprecations: Vec<(SharedString, SharedString)>,
} }
impl Default for ActionRegistry { impl Default for ActionRegistry {
@ -93,6 +102,7 @@ impl Default for ActionRegistry {
builders_by_name: Default::default(), builders_by_name: Default::default(),
names_by_type_id: Default::default(), names_by_type_id: Default::default(),
all_names: Default::default(), all_names: Default::default(),
deprecations: Default::default(),
}; };
this.load_actions(); this.load_actions();
@ -111,6 +121,7 @@ pub type MacroActionBuilder = fn() -> ActionData;
#[doc(hidden)] #[doc(hidden)]
pub struct ActionData { pub struct ActionData {
pub name: &'static str, pub name: &'static str,
pub aliases: &'static [&'static str],
pub type_id: TypeId, pub type_id: TypeId,
pub build: ActionBuilder, pub build: ActionBuilder,
} }
@ -134,6 +145,7 @@ impl ActionRegistry {
pub(crate) fn load_action<A: Action>(&mut self) { pub(crate) fn load_action<A: Action>(&mut self) {
self.insert_action(ActionData { self.insert_action(ActionData {
name: A::debug_name(), name: A::debug_name(),
aliases: A::deprecated_aliases(),
type_id: TypeId::of::<A>(), type_id: TypeId::of::<A>(),
build: A::build, build: A::build,
}); });
@ -142,6 +154,10 @@ impl ActionRegistry {
fn insert_action(&mut self, action: ActionData) { fn insert_action(&mut self, action: ActionData) {
let name: SharedString = action.name.into(); let name: SharedString = action.name.into();
self.builders_by_name.insert(name.clone(), action.build); self.builders_by_name.insert(name.clone(), action.build);
for &alias in action.aliases {
self.builders_by_name.insert(alias.into(), action.build);
self.deprecations.push((alias.into(), name.clone()));
}
self.names_by_type_id.insert(action.type_id, name.clone()); self.names_by_type_id.insert(action.type_id, name.clone());
self.all_names.push(name); self.all_names.push(name);
} }
@ -174,6 +190,10 @@ impl ActionRegistry {
pub fn all_action_names(&self) -> &[SharedString] { pub fn all_action_names(&self) -> &[SharedString] {
self.all_names.as_slice() self.all_names.as_slice()
} }
pub fn action_deprecations(&self) -> &[(SharedString, SharedString)] {
self.deprecations.as_slice()
}
} }
/// Defines unit structs that can be used as actions. /// Defines unit structs that can be used as actions.
@ -206,7 +226,7 @@ macro_rules! actions {
/// `impl_action_as!` /// `impl_action_as!`
#[macro_export] #[macro_export]
macro_rules! action_as { macro_rules! action_as {
($namespace:path, $name:ident as $visual_name:tt) => { ($namespace:path, $name:ident as $visual_name:ident) => {
#[doc = "The `"] #[doc = "The `"]
#[doc = stringify!($name)] #[doc = stringify!($name)]
#[doc = "` action, see [`gpui::actions!`]"] #[doc = "` action, see [`gpui::actions!`]"]
@ -228,6 +248,43 @@ macro_rules! action_as {
}; };
} }
/// Defines a unit struct that can be used as an action, with some deprecated aliases.
#[macro_export]
macro_rules! action_aliases {
($namespace:path, $name:ident, [$($alias:ident),* $(,)?]) => {
#[doc = "The `"]
#[doc = stringify!($name)]
#[doc = "` action, see [`gpui::actions!`]"]
#[derive(
::std::cmp::PartialEq,
::std::clone::Clone,
::std::default::Default,
::std::fmt::Debug,
gpui::private::serde_derive::Deserialize,
)]
#[serde(crate = "gpui::private::serde")]
pub struct $name;
gpui::__impl_action!(
$namespace,
$name,
$name,
fn build(
_: gpui::private::serde_json::Value,
) -> gpui::Result<::std::boxed::Box<dyn gpui::Action>> {
Ok(Box::new(Self))
},
fn deprecated_aliases() -> &'static [&'static str] {
&[
$(concat!(stringify!($namespace), "::", stringify!($alias))),*
]
}
);
gpui::register_action!($name);
};
}
/// Implements the Action trait for any struct that implements Clone, Default, PartialEq, and serde_deserialize::Deserialize /// Implements the Action trait for any struct that implements Clone, Default, PartialEq, and serde_deserialize::Deserialize
#[macro_export] #[macro_export]
macro_rules! impl_actions { macro_rules! impl_actions {
@ -269,7 +326,7 @@ macro_rules! impl_action_as {
#[doc(hidden)] #[doc(hidden)]
#[macro_export] #[macro_export]
macro_rules! __impl_action { macro_rules! __impl_action {
($namespace:path, $name:ident, $visual_name:tt, $build:item) => { ($namespace:path, $name:ident, $visual_name:tt, $($items:item),*) => {
impl gpui::Action for $name { impl gpui::Action for $name {
fn name(&self) -> &'static str fn name(&self) -> &'static str
{ {
@ -291,8 +348,6 @@ macro_rules! __impl_action {
) )
} }
$build
fn partial_eq(&self, action: &dyn gpui::Action) -> bool { fn partial_eq(&self, action: &dyn gpui::Action) -> bool {
action action
.as_any() .as_any()
@ -307,6 +362,8 @@ macro_rules! __impl_action {
fn as_any(&self) -> &dyn ::std::any::Any { fn as_any(&self) -> &dyn ::std::any::Any {
self self
} }
$($items)*
} }
}; };
} }

View file

@ -1226,6 +1226,11 @@ impl AppContext {
self.actions.all_action_names() self.actions.all_action_names()
} }
/// Get a list of all deprecated action aliases and their canonical names.
pub fn action_deprecations(&self) -> &[(SharedString, SharedString)] {
self.actions.action_deprecations()
}
/// Register a callback to be invoked when the application is about to quit. /// Register a callback to be invoked when the application is about to quit.
/// It is not possible to cancel the quit event at this point. /// It is not possible to cancel the quit event at this point.
pub fn on_app_quit<Fut>( pub fn on_app_quit<Fut>(

View file

@ -134,8 +134,6 @@ impl Keymap {
/// If a user has disabled a binding with `"x": null` it will not be returned. Disabled /// If a user has disabled a binding with `"x": null` it will not be returned. Disabled
/// bindings are evaluated with the same precedence rules so you can disable a rule in /// bindings are evaluated with the same precedence rules so you can disable a rule in
/// a given context only. /// a given context only.
///
/// In the case of multi-key bindings, the
pub fn bindings_for_input( pub fn bindings_for_input(
&self, &self,
input: &[Keystroke], input: &[Keystroke],

View file

@ -32,6 +32,7 @@ pub(crate) fn register_action(type_name: &Ident) -> proc_macro2::TokenStream {
fn #action_builder_fn_name() -> gpui::ActionData { fn #action_builder_fn_name() -> gpui::ActionData {
gpui::ActionData { gpui::ActionData {
name: <#type_name as gpui::Action>::debug_name(), name: <#type_name as gpui::Action>::debug_name(),
aliases: <#type_name as gpui::Action>::deprecated_aliases(),
type_id: ::std::any::TypeId::of::<#type_name>(), type_id: ::std::any::TypeId::of::<#type_name>(),
build: <#type_name as gpui::Action>::build, build: <#type_name as gpui::Action>::build,
} }

View file

@ -76,6 +76,7 @@ impl JsonLspAdapter {
fn get_workspace_config(language_names: Vec<String>, cx: &mut AppContext) -> Value { fn get_workspace_config(language_names: Vec<String>, cx: &mut AppContext) -> Value {
let action_names = cx.all_action_names(); let action_names = cx.all_action_names();
let deprecations = cx.action_deprecations();
let font_names = &cx.text_system().all_font_names(); let font_names = &cx.text_system().all_font_names();
let settings_schema = cx.global::<SettingsStore>().json_schema( let settings_schema = cx.global::<SettingsStore>().json_schema(
@ -116,7 +117,7 @@ impl JsonLspAdapter {
}, },
{ {
"fileMatch": [schema_file_match(paths::keymap_file())], "fileMatch": [schema_file_match(paths::keymap_file())],
"schema": KeymapFile::generate_json_schema(action_names), "schema": KeymapFile::generate_json_schema(action_names, deprecations),
}, },
{ {
"fileMatch": [ "fileMatch": [

View file

@ -5,7 +5,7 @@ use gpui::{Action, AppContext, KeyBinding, SharedString};
use schemars::{ use schemars::{
gen::{SchemaGenerator, SchemaSettings}, gen::{SchemaGenerator, SchemaSettings},
schema::{InstanceType, Schema, SchemaObject, SingleOrVec, SubschemaValidation}, schema::{InstanceType, Schema, SchemaObject, SingleOrVec, SubschemaValidation},
JsonSchema, JsonSchema, Map,
}; };
use serde::Deserialize; use serde::Deserialize;
use serde_json::Value; use serde_json::Value;
@ -139,34 +139,51 @@ impl KeymapFile {
Ok(()) Ok(())
} }
pub fn generate_json_schema(action_names: &[SharedString]) -> serde_json::Value { pub fn generate_json_schema(
action_names: &[SharedString],
deprecations: &[(SharedString, SharedString)],
) -> serde_json::Value {
let mut root_schema = SchemaSettings::draft07() let mut root_schema = SchemaSettings::draft07()
.with(|settings| settings.option_add_null_type = false) .with(|settings| settings.option_add_null_type = false)
.into_generator() .into_generator()
.into_root_schema_for::<KeymapFile>(); .into_root_schema_for::<KeymapFile>();
let mut alternatives = vec![
Schema::Object(SchemaObject {
instance_type: Some(SingleOrVec::Single(Box::new(InstanceType::String))),
enum_values: Some(
action_names
.iter()
.map(|name| Value::String(name.to_string()))
.collect(),
),
..Default::default()
}),
Schema::Object(SchemaObject {
instance_type: Some(SingleOrVec::Single(Box::new(InstanceType::Array))),
..Default::default()
}),
Schema::Object(SchemaObject {
instance_type: Some(SingleOrVec::Single(Box::new(InstanceType::Null))),
..Default::default()
}),
];
for (old, new) in deprecations {
alternatives.push(Schema::Object(SchemaObject {
instance_type: Some(SingleOrVec::Single(Box::new(InstanceType::String))),
const_value: Some(Value::String(old.to_string())),
extensions: Map::from_iter([(
// deprecationMessage is not part of the JSON Schema spec,
// but json-language-server recognizes it.
"deprecationMessage".to_owned(),
format!("Deprecated, use {new}").into(),
)]),
..Default::default()
}));
}
let action_schema = Schema::Object(SchemaObject { let action_schema = Schema::Object(SchemaObject {
subschemas: Some(Box::new(SubschemaValidation { subschemas: Some(Box::new(SubschemaValidation {
one_of: Some(vec![ one_of: Some(alternatives),
Schema::Object(SchemaObject {
instance_type: Some(SingleOrVec::Single(Box::new(InstanceType::String))),
enum_values: Some(
action_names
.iter()
.map(|name| Value::String(name.to_string()))
.collect(),
),
..Default::default()
}),
Schema::Object(SchemaObject {
instance_type: Some(SingleOrVec::Single(Box::new(InstanceType::Array))),
..Default::default()
}),
Schema::Object(SchemaObject {
instance_type: Some(SingleOrVec::Single(Box::new(InstanceType::Null))),
..Default::default()
}),
]),
..Default::default() ..Default::default()
})), })),
..Default::default() ..Default::default()