|
3 | 3 | #include <Config/RapidJSON.h>
|
4 | 4 | #include "ActionsShortcutsManager.h"
|
5 | 5 | #include <assert.h>
|
| 6 | +#include <frozen/unordered_map.h> |
| 7 | +#include <frozen/string.h> |
6 | 8 |
|
7 | 9 | // this key should not exist in config defaults
|
8 | 10 | static const auto g_OverridesConfigPath = "hotkeyOverrides_v1";
|
9 | 11 |
|
10 | 12 | // clang-format off
|
11 | 13 | // the persistance holy grail is below, change ids only in emergency case:
|
12 |
| -[[clang::no_destroy]] static const std::vector<std::pair<const char*,int>> g_ActionsTags = { |
| 14 | +static constexpr std::pair<const char*,int> g_ActionsTags[] = { |
13 | 15 | {"menu.nimble_commander.about", 10'000},
|
14 | 16 | {"menu.nimble_commander.preferences", 10'010},
|
15 | 17 | {"menu.nimble_commander.hide", 10'020},
|
|
213 | 215 | {"viewer.refresh", 101'005}
|
214 | 216 | };
|
215 | 217 |
|
216 |
| -[[clang::no_destroy]] static const std::vector<std::pair<const char*, const char8_t*>> g_DefaultShortcuts = { |
| 218 | +static constinit std::pair<const char*, const char8_t*> g_DefaultShortcuts[] = { |
217 | 219 | {"menu.nimble_commander.about", u8"" },
|
218 | 220 | {"menu.nimble_commander.preferences", u8"⌘," }, // cmd+,
|
219 | 221 | {"menu.nimble_commander.toggle_admin_mode", u8"" },
|
220 | 222 | {"menu.nimble_commander.hide", u8"⌘h" }, // cmd+h
|
221 | 223 | {"menu.nimble_commander.hide_others", u8"⌥⌘h" }, // cmd+alt+h
|
222 | 224 | {"menu.nimble_commander.show_all", u8"" },
|
223 | 225 | {"menu.nimble_commander.quit", u8"⌘q" }, // cmd+q
|
224 |
| - {"menu.nimble_commander.active_license_file", u8"" }, |
225 |
| - {"menu.nimble_commander.purchase_license", u8"" }, |
226 |
| - {"menu.nimble_commander.purchase_pro_features", u8"" }, |
227 |
| - {"menu.nimble_commander.restore_purchases", u8"" }, |
228 |
| - {"menu.nimble_commander.registration_info", u8"" }, |
| 226 | + {"menu.nimble_commander.active_license_file", u8"" }, // no longer used |
| 227 | + {"menu.nimble_commander.purchase_license", u8"" }, // no longer used |
| 228 | + {"menu.nimble_commander.purchase_pro_features", u8"" }, // no longer used |
| 229 | + {"menu.nimble_commander.restore_purchases", u8"" }, // no longer used |
| 230 | + {"menu.nimble_commander.registration_info", u8"" }, // no longer used |
229 | 231 |
|
230 | 232 | {"menu.file.newwindow", u8"⌘n" }, // cmd+n
|
231 | 233 | {"menu.file.new_folder", u8"⇧⌘n" }, // cmd+shift+n
|
|
410 | 412 | };
|
411 | 413 | // clang-format on
|
412 | 414 |
|
| 415 | +static constinit const auto g_ActionToTag = [] { |
| 416 | + std::pair<frozen::string, int> items[std::size(g_ActionsTags)] = { |
| 417 | + [0 ... std::size(g_ActionsTags) - 1] = {frozen::string(""), 0}}; |
| 418 | + for( size_t i = 0; i < std::size(g_ActionsTags); ++i ) |
| 419 | + items[i] = std::pair<frozen::string, int>(g_ActionsTags[i].first, g_ActionsTags[i].second); |
| 420 | + return frozen::make_unordered_map(items); |
| 421 | +}(); |
| 422 | + |
| 423 | +static constinit const auto g_TagToAction = [] { |
| 424 | + std::pair<int, frozen::string> items[std::size(g_ActionsTags)] = { |
| 425 | + [0 ... std::size(g_ActionsTags) - 1] = {0, frozen::string("")}}; |
| 426 | + for( size_t i = 0; i < std::size(g_ActionsTags); ++i ) |
| 427 | + items[i] = std::pair<int, frozen::string>(g_ActionsTags[i].second, g_ActionsTags[i].first); |
| 428 | + return frozen::make_unordered_map(items); |
| 429 | +}(); |
| 430 | + |
413 | 431 | ActionsShortcutsManager::ShortCutsUpdater::ShortCutsUpdater(std::span<const UpdateTarget> _targets)
|
414 | 432 | {
|
415 | 433 | auto &am = ActionsShortcutsManager::Instance();
|
|
430 | 448 |
|
431 | 449 | ActionsShortcutsManager::ActionsShortcutsManager()
|
432 | 450 | {
|
433 |
| - for( auto &p : g_ActionsTags ) { |
434 |
| - // safety checks against malformed g_ActionsTags |
435 |
| - assert(m_TagToAction.count(p.second) == 0); |
436 |
| - assert(m_ActionToTag.count(p.first) == 0); |
437 |
| - |
438 |
| - m_TagToAction[p.second] = p.first; |
439 |
| - m_ActionToTag[p.first] = p.second; |
440 |
| - } |
| 451 | + // safety checks against malformed g_ActionsTags, only in Debug builds |
| 452 | + assert( |
| 453 | + (robin_hood::unordered_map<std::string_view, int>{std::begin(g_ActionsTags), std::end(g_ActionsTags)}).size() == |
| 454 | + std::size(g_ActionsTags)); |
441 | 455 |
|
442 | 456 | for( auto &d : g_DefaultShortcuts ) {
|
443 |
| - auto i = m_ActionToTag.find(d.first); |
444 |
| - if( i != end(m_ActionToTag) ) |
445 |
| - m_ShortCutsDefaults[i->second] = nc::utility::ActionShortcut{d.second}; |
| 457 | + auto i = g_ActionToTag.find(std::string_view{d.first}); |
| 458 | + if( i != g_ActionToTag.end() ) |
| 459 | + m_ShortCutsDefaults[i->second] = nc::utility::ActionShortcut{d.second}; |
446 | 460 | }
|
447 | 461 |
|
448 | 462 | ReadOverrideFromConfig();
|
|
456 | 470 |
|
457 | 471 | int ActionsShortcutsManager::TagFromAction(std::string_view _action) const noexcept
|
458 | 472 | {
|
459 |
| - auto it = m_ActionToTag.find(_action); |
460 |
| - if( it != std::end(m_ActionToTag) ) |
461 |
| - return it->second; |
462 |
| - return -1; |
| 473 | + const auto it = g_ActionToTag.find(_action); |
| 474 | + return it == g_ActionToTag.end() ? -1 : it->second; |
463 | 475 | }
|
464 | 476 |
|
465 |
| -std::string ActionsShortcutsManager::ActionFromTag(int _tag) const |
| 477 | +std::string_view ActionsShortcutsManager::ActionFromTag(int _tag) const noexcept |
466 | 478 | {
|
467 |
| - auto it = m_TagToAction.find(_tag); |
468 |
| - if( it != end(m_TagToAction) ) |
469 |
| - return it->second; |
470 |
| - return ""; |
| 479 | + const auto it = g_TagToAction.find(_tag); |
| 480 | + return it == g_TagToAction.end() ? "" : std::string_view{it->second.data(), it->second.size()}; |
471 | 481 | }
|
472 | 482 |
|
473 | 483 | void ActionsShortcutsManager::SetMenuShortCuts(NSMenu *_menu) const
|
|
488 | 498 | if( sc != m_ShortCutsDefaults.end() ) {
|
489 | 499 | [i nc_setKeyEquivalentWithShortcut:sc->second];
|
490 | 500 | }
|
491 |
| - else if( m_TagToAction.find(tag) != m_TagToAction.end() ) { |
| 501 | + else if( g_TagToAction.find(tag) != g_TagToAction.end() ) { |
492 | 502 | [i nc_setKeyEquivalentWithShortcut:nc::utility::ActionShortcut{}];
|
493 | 503 | }
|
494 | 504 | }
|
|
507 | 517 | m_ShortCutsOverrides.clear();
|
508 | 518 | for( auto i = v.MemberBegin(), e = v.MemberEnd(); i != e; ++i )
|
509 | 519 | if( i->name.GetType() == kStringType && i->value.GetType() == kStringType ) {
|
510 |
| - auto att = m_ActionToTag.find(i->name.GetString()); |
511 |
| - if( att != m_ActionToTag.end() ) |
| 520 | + auto att = g_ActionToTag.find(std::string_view{i->name.GetString()}); |
| 521 | + if( att != g_ActionToTag.end() ) |
512 | 522 | m_ShortCutsOverrides[att->second] = nc::utility::ActionShortcut{i->value.GetString()};
|
513 | 523 | }
|
514 | 524 | }
|
515 | 525 |
|
516 |
| -ActionsShortcutsManager::ShortCut |
517 |
| -ActionsShortcutsManager::ShortCutFromAction(std::string_view _action) const noexcept |
| 526 | +ActionsShortcutsManager::ShortCut ActionsShortcutsManager::ShortCutFromAction(std::string_view _action) const noexcept |
518 | 527 | {
|
519 | 528 | int tag = TagFromAction(_action);
|
520 | 529 | if( tag <= 0 )
|
|
544 | 553 | return {};
|
545 | 554 | }
|
546 | 555 |
|
547 |
| -bool ActionsShortcutsManager::SetShortCutOverride(const std::string &_action, const ShortCut &_sc) |
| 556 | +bool ActionsShortcutsManager::SetShortCutOverride(const std::string_view _action, const ShortCut &_sc) |
548 | 557 | {
|
549 | 558 | const auto tag = TagFromAction(_action);
|
550 | 559 | if( tag <= 0 )
|
|
605 | 614 | return g_ActionsTags;
|
606 | 615 | }
|
607 | 616 |
|
608 |
| -ActionsShortcutsManager::ObservationTicket |
609 |
| -ActionsShortcutsManager::ObserveChanges(std::function<void()> _callback) |
| 617 | +ActionsShortcutsManager::ObservationTicket ActionsShortcutsManager::ObserveChanges(std::function<void()> _callback) |
610 | 618 | {
|
611 | 619 | return ObservableBase::AddObserver(_callback);
|
612 | 620 | }
|
0 commit comments