diff --git a/check_targets.jai b/check_targets.jai index e416c87..8b4f66b 100644 --- a/check_targets.jai +++ b/check_targets.jai @@ -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; diff --git a/first.jai b/first.jai index 121cbb9..d5683f0 100644 --- a/first.jai +++ b/first.jai @@ -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"; diff --git a/src/test/logger_tests.jai b/src/test/logger_tests.jai index df5bfe1..8266387 100644 --- a/src/test/logger_tests.jai +++ b/src/test/logger_tests.jai @@ -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 diff --git a/src/ui/imgui_keyboard.jai b/src/ui/imgui_keyboard.jai index b3fc40a..b3aa749 100644 --- a/src/ui/imgui_keyboard.jai +++ b/src/ui/imgui_keyboard.jai @@ -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 diff --git a/src/ui/imgui_theme_registry.jai b/src/ui/imgui_theme_registry.jai index 5044433..7034ac5 100644 --- a/src/ui/imgui_theme_registry.jai +++ b/src/ui/imgui_theme_registry.jai @@ -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();