-
Notifications
You must be signed in to change notification settings - Fork 8.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Introduce serialization for actions #9926
Conversation
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
5d0a656
to
3b99fde
Compare
a6b5bde
to
0068ae0
Compare
0068ae0
to
9cb377e
Compare
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I only really have the one main question that I want answered. Otherwise, the rest seems pretty straightforward.
We should make sure to add a test for #9926 (comment) as well, because it's a good edge case
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🙌 on the ACTION_TO_SERIALIZERS_PAIR
thing, and thanks for adding the test!
This bug was caused by the list of |
#undef ON_ALL_ACTIONS | ||
}; | ||
|
||
static const std::map<ShortcutAction, std::string_view, std::less<>> ActionToStringMap{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have got to stop it with the globally initialized maps. Sorry. This looks like a case for til::static_map or til::presorted_static_map. I'd rather do that than have yet another static initializer 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should I do what we did with GeneratedActionNames
in ActionAndArgs::GenerateName
? Define these in the function they're used as static lambda functions. Or does that not make this any better?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@DHowett Can you explain the problem with static initializers for the uninitiated? 🙂
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure!
Initializing a static non-constexpr value at file scope generates a block of code that must be executed when the library is loaded, every time it is loaded. For something like the settings model, that cost is paid once on startup, but it is still a cost that must be paid before any of the actual settings model code is run.
constexpr is a different story: those are evaluated at compile time and stored permanently in the binary.
For a really, really good example of the cost of a static initializer (or something very similar) and the payback you get from replacing it with a fully-constexpr data store, look at commit 16e1e29.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems fairly solid - it even offers perfect hash functions: https://github.com/serge-sans-paille/frozen
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Leonard and I couldn't get this to work, unfortunately. We kept running into til::presorted_static_map
saying that it couldn't find the static_map
in the ctor or something like that. Sorry!
The problem is the static map, not the functions.
|
## Summary of the Pull Request This PR lays the foundation for a new Actions page in the Settings UI as designed in #6900. The Actions page now leverages the `ActionMap` to display all of the key bindings and allow the user to modify the associated key chord or delete the key binding entirely. ## References #9621 - ActionMap #9926 - ActionMap serialization #9428 - ActionMap Spec #6900 - Actions page #9427 - Actions page design doc ## Detailed Description of the Pull Request / Additional comments ### Settings Model Changes - `Command::Copy()` now copies the `ActionAndArgs` - `ActionMap::RebindKeys()` handles changing the key chord of a key binding. If a conflict occurs, the conflicting key chord is overwritten. - `ActionMap::DeleteKeyBinding()` "deletes" a key binding by binding "unbound" to the given key chord. - `ActionMap::KeyBindings()` presents another view (similar to `NameMap`) of the `ActionMap`. It specifically presents a map of key chords to commands. It is generated similar to how `NameMap` is generated. ### Editor Changes - `Actions.xaml` is mainly split into two parts: - `ListView` (as before) holds the list of key bindings. We _could_ explore the idea of an items repeater, but the `ListView` seems to provide some niceties with regards to navigating the list via the key board (though none are selectable). - `DataTemplate` is used to represent each key binding inside the `ListView`. This is tricky because it is bound to a `KeyBindingViewModel` which must provide _all_ context necessary to modify the UI and the settings model. We cannot use names to target UI elements inside this template, so we must make the view model smart and force updates to the UI via changes in the view model. - `KeyBindingViewModel` is a view model object that controls the UI and the settings model. There are a number of TODOs in Actions.cpp will be long-term follow-ups and would be nice to have. This includes... - a binary search by name on `Actions::KeyBindingList` - presenting an error when the provided key chord is invalid. ## Demo ![Actions Page Demo](https://user-images.githubusercontent.com/11050425/116034988-131d1b80-a619-11eb-8df2-c7e57c6fad86.gif)
Hello @carlos-zamora! Because this pull request has the p.s. you can customize the way I help with merging this pull request, such as holding this pull request until a specific person approves. Simply @mention me (
|
🎉 Handy links: |
Summary of the Pull Request
This PR builds on the
ActionMap
PR (#6900) by leveragingActionMap
to serialize actions. From the top down, the process is now as follows:CascadiaSettings
: remove the hack of copying whatever we had for actions before.GlobalAppSettings
: serialize theActionMap
to"actions": []
ActionMap
: iterate over the internal_ActionMap
(list of actions) and serialize eachCommand
Command
: THIS IS WHERE THE MAGIC HAPPENS! For each key mapping, serialize an action. Only the first one needs to include the name and icon.ActionAndArgs
: Find the relevantIActionArgs
parser and serialize theActionAndArgs
.ActionArgs
: ANNOYING CHANGE Serialize any args that are set. We need each setting to be saved as astd::optional
. As with inheritance, this allows us to distinguish an explicit setting to the default value (sometimesnull
) vs an implicit "give me the default value". This allows us to serialize only the relevant details of each action, rather than writing all of the args.References
Validation Steps Performed
Tests added!