[0.1.19] Install a new hotkey's default when it is added to settings.config

hotkeys_missing_lines writes the shipped default of an action the file does not mention, but that
save records the hash of what it wrote, so the file was not reloaded and the action stayed unbound
until the file next changed. The bindings installed at startup and on reload now include those
defaults (hotkeys_with_missing_defaults), as in Ex4 1.47.2; a file of an older version still gets
"none". A logger test covers it.
This commit is contained in:
Musa Mahmood 2026-10-14 18:50:34 +01:00
parent 120eba1e23
commit c4203cc8cf
5 changed files with 62 additions and 10 deletions

View File

@ -47,7 +47,7 @@ APP_NAME :: "mcap";
APP_FOLDER_NAME :: "mcap";
GIT_BRANCH :: "check";
GIT_HASH :: "-";
VERSION :: "0.1.18";
VERSION :: "0.1.19";
BUILD_DATE :: "-";
DEBUG :: true;
COMPILE_TESTS :: true;

View File

@ -8,7 +8,7 @@ APP_NAME :: "mcap";
APP_FOLDER_NAME :: "mcap";
APP_BUNDLE_IDENTIFIER :: "com.example.mcap";
VERSION :: "0.1.18";
VERSION :: "0.1.19";
// Where everything goes: bin/, or bin-headless/ for builds made with no_crash_dialog, so automated
// builds never write over the ones you run by hand.
build_directory := "bin";

View File

@ -229,6 +229,38 @@ settings_tests :: () {
defer settings_free(*settings);
expect(ok && !seen.event_log && settings.event_log_capacity == EVENT_LOG_CAPACITY_DEFAULT,
"a file without the key gave seen % and capacity %", seen.event_log, settings.event_log_capacity);
// A section that does not mention an action gets its default installed right away, since the save
// that writes it into the file does not reload it; a pre-upgrade file gets "none" instead.
{
group("hotkeys missing from [hotkeys]");
hotkey_actions_init();
defaults := hotkey_defaults();
bindings: [..] Hotkey_Binding;
bindings.allocator = temp;
errors := hotkeys_parse_section("logger_tests", "[hotkeys]\nCtrl-Shift-Q program_exit\nnone minimize_to_tray\n", hotkey_actions, *bindings);
expect(errors == 0 && bindings.count == 2, "the partial section gave % bindings and % errors", bindings.count, errors);
exit_action := hotkey_find_action(hotkey_actions, "program_exit");
minimize := hotkey_find_action(hotkey_actions, "minimize_to_tray");
focus_search := hotkey_find_action(hotkey_actions, "focus_search");
installed := hotkeys_with_missing_defaults(hotkey_actions, bindings, defaults, APP_USER_SETTINGS_VERSION);
count_for :: (bindings: [] Hotkey_Binding, action: s32) -> int {
count := 0;
for bindings if it.action == action count += 1;
return count;
}
expect(count_for(installed, exit_action) == 1, "program_exit has % bindings, not just its own 1", count_for(installed, exit_action));
expect(count_for(installed, minimize) == 1, "minimize_to_tray's \"none\" was joined by % more", count_for(installed, minimize) - 1);
expect(count_for(installed, focus_search) == count_for(defaults, focus_search) && count_for(defaults, focus_search) > 0,
"focus_search got % of its % default bindings", count_for(installed, focus_search), count_for(defaults, focus_search));
missing, _ := hotkeys_missing_lines(hotkey_actions, installed, defaults, APP_USER_SETTINGS_VERSION);
expect(missing == "", "with the defaults added, these are still missing:%", missing);
old := hotkeys_with_missing_defaults(hotkey_actions, bindings, defaults, APP_USER_SETTINGS_VERSION - 1);
expect(old.count == bindings.count, "a pre-upgrade file got % default bindings", old.count - bindings.count);
}
}
#scope_export

View File

@ -293,9 +293,7 @@ hotkeys_missing_lines :: (actions: [] Hotkey_Action, bindings: [] Hotkey_Binding
new_active_count := 0;
for action, action_index: actions {
mentioned := false;
for bindings if it.action == action_index { mentioned = true; break; }
if mentioned continue;
if hotkeys_mention_action(bindings, action_index) continue;
if !header_written {
append(*builder, "\n# Added automatically; new since this file was last saved.\n");
@ -314,6 +312,28 @@ hotkeys_missing_lines :: (actions: [] Hotkey_Action, bindings: [] Hotkey_Binding
return builder_to_string(*builder,, temp), new_active_count;
}
// The bindings to install for a section as read: its own, plus the shipped defaults of the actions
// it does not mention, which hotkeys_missing_lines gives the file in the save that follows. That
// save records the hash of what it wrote, so the file is not reloaded, and without these a new
// action would stay unbound until the file next changed. temp.
hotkeys_with_missing_defaults :: (actions: [] Hotkey_Action, bindings: [] Hotkey_Binding, defaults: [] Hotkey_Binding, file_version: s64) -> [] Hotkey_Binding {
if file_version < APP_USER_SETTINGS_VERSION return bindings; // these get "none"
result: [..] Hotkey_Binding;
result.allocator = temp;
array_add(*result, ..bindings);
for action, action_index: actions {
if hotkeys_mention_action(bindings, action_index) continue;
for defaults if it.action == action_index array_add(*result, it);
}
return result;
}
hotkeys_mention_action :: (bindings: [] Hotkey_Binding, action_index: int) -> bool {
for bindings if it.action == action_index return true;
return false;
}
// ---------------------------------------------------------------- the [global_hotkeys] section
// Registered with the OS, so they fire from any app: RegisterHotKey on Windows, Carbon's

View File

@ -366,11 +366,11 @@ app_load_user_settings_file :: () -> write_back: bool {
bindings: [] Hotkey_Binding = hotkey_defaults();
if ok && seen.hotkeys bindings = app_user_settings.hotkey_bindings;
hotkeys_install(bindings);
hotkeys_install(hotkeys_with_missing_defaults(hotkey_actions, bindings, hotkey_defaults(), version));
global_bindings: [] Hotkey_Binding = global_hotkey_defaults();
if ok && seen.global_hotkeys global_bindings = app_user_settings.global_hotkey_bindings;
global_hotkeys_install(global_bindings);
global_hotkeys_install(hotkeys_with_missing_defaults(global_hotkey_actions, global_bindings, global_hotkey_defaults(), version));
if !ok return false;
@ -804,7 +804,7 @@ app_reload_user_settings_if_changed :: () {
settings_file_hash = hash;
fresh: App_User_Settings;
ok, seen, _ := settings_parse(path, file_data, *fresh);
ok, seen, version := settings_parse(path, file_data, *fresh);
if !ok {
settings_free(*fresh);
log_error("[settings] Could not apply the changes to %; keeping the current settings.", path);
@ -832,11 +832,11 @@ app_reload_user_settings_if_changed :: () {
bindings: [] Hotkey_Binding = hotkey_defaults();
if seen.hotkeys bindings = app_user_settings.hotkey_bindings;
hotkeys_install(bindings);
hotkeys_install(hotkeys_with_missing_defaults(hotkey_actions, bindings, hotkey_defaults(), version));
global_bindings: [] Hotkey_Binding = global_hotkey_defaults();
if seen.global_hotkeys global_bindings = app_user_settings.global_hotkey_bindings;
global_hotkeys_install(global_bindings);
global_hotkeys_install(hotkeys_with_missing_defaults(global_hotkey_actions, global_bindings, global_hotkey_defaults(), version));
global_hotkeys_reapply();
settings_note_synced();