From a1162c22563243ef639eb2253a52fcecdd5bc644 Mon Sep 17 00:00:00 2001 From: Robbert van der Helm Date: Tue, 13 Oct 2020 14:20:51 +0200 Subject: [PATCH] Print invalid and unknown options on startup --- CHANGELOG.md | 3 +++ src/common/configuration.cpp | 31 +++++++++++++++++++++++++------ src/common/configuration.h | 18 ++++++++++++++++++ src/plugin/plugin-bridge.cpp | 31 ++++++++++++++++++++++--------- src/plugin/utils.cpp | 11 +++++++++++ src/plugin/utils.h | 8 ++++++++ 6 files changed, 87 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f9c6eb02..5ca194b6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,9 @@ Versioning](https://semver.org/spec/v2.0.0.html). to type text with spaces inside of a plugin editor window. Please let me know if this causes any issues and we'll try to come up with a middle ground. +- Both unrecognized and invalid options will now be printed on started to make + debugging easier. + - Added a note to the message saying that libSwell GUI support has been disabled that his is perfectly normal when using REAPER. The message now also contains the suggestion to enable the `hack_reaper_update_display` workaround for diff --git a/src/common/configuration.cpp b/src/common/configuration.cpp index e1c5713b..b8c5161e 100644 --- a/src/common/configuration.cpp +++ b/src/common/configuration.cpp @@ -75,12 +75,31 @@ Configuration::Configuration(const fs::path& config_path, matched_pattern = pattern; // If the table is missing some fields then they will simply be left at - // their defaults - editor_double_embed = - table["editor_double_embed"].value().value_or(false); - hack_reaper_update_display = - table["hack_reaper_update_display"].value().value_or(false); - group = table["group"].value(); + // their defaults. At this point I'd really wish C++ could do pattern + // matching. + for (const auto& [key, value] : table) { + if (key == "editor_double_embed") { + if (const auto parsed_value = value.as_boolean()) { + editor_double_embed = parsed_value->get(); + } else { + invalid_options.push_back(key); + } + } else if (key == "hack_reaper_update_display") { + if (const auto parsed_value = value.as_boolean()) { + hack_reaper_update_display = parsed_value->get(); + } else { + invalid_options.push_back(key); + } + } else if (key == "group") { + if (const auto parsed_value = value.as_string()) { + group = parsed_value->get(); + } else { + invalid_options.push_back(key); + } + } else { + unknown_options.push_back(key); + } + } break; } diff --git a/src/common/configuration.h b/src/common/configuration.h index 5437e484..68d9e357 100644 --- a/src/common/configuration.h +++ b/src/common/configuration.h @@ -112,6 +112,19 @@ class Configuration { */ std::optional matched_pattern; + /** + * Options with a wrong argument type. These will be printed separately from + * `unknown_options` to avoid confusion. + */ + std::vector invalid_options; + + /** + * Unrecognized configuration options, likely caused by an old option that + * served as a hack or a workaround getting removed. Will be printed on + * startup when not empty. + */ + std::vector unknown_options; + template void serialize(S& s) { s.value1b(editor_double_embed); @@ -122,5 +135,10 @@ class Configuration { [](S& s, auto& v) { s.ext(v, bitsery::ext::BoostPath()); }); s.ext(matched_pattern, bitsery::ext::StdOptional(), [](S& s, auto& v) { s.text1b(v, 4096); }); + + s.container(invalid_options, 1024, + [](S& s, auto& v) { s.text1b(v, 4096); }); + s.container(unknown_options, 1024, + [](S& s, auto& v) { s.text1b(v, 4096); }); } }; diff --git a/src/plugin/plugin-bridge.cpp b/src/plugin/plugin-bridge.cpp index 3e17c666..886abeec 100644 --- a/src/plugin/plugin-bridge.cpp +++ b/src/plugin/plugin-bridge.cpp @@ -684,20 +684,33 @@ void PluginBridge::log_init_message() { } init_msg << "'" << std::endl; - bool other_options_set = false; - init_msg << "other options: '"; + init_msg << "other options: "; + std::vector other_options; if (config.editor_double_embed) { - init_msg << "editor: double embed"; - other_options_set = true; + other_options.push_back("editor: double embed"); } if (config.hack_reaper_update_display) { - init_msg << "hack: REAPER 'audioMasterUpdateDisplay' workaround"; - other_options_set = true; + other_options.push_back( + "hack: REAPER audioMasterUpdateDisplay() workaround"); } - if (!other_options_set) { - init_msg << ""; + if (!other_options.empty()) { + init_msg << join_quoted_strings(other_options) << std::endl; + } else { + init_msg << "''" << std::endl; + } + + // To make debugging easier, we'll print both unrecognized options (that + // might be left over when an option gets removed) as well as options have + // the wrong argument types + if (!config.invalid_options.empty()) { + init_msg << "invalid arguments: " + << join_quoted_strings(config.invalid_options) + << " (check the readme for more information)" << std::endl; + } + if (!config.unknown_options.empty()) { + init_msg << "unrecognized options: " + << join_quoted_strings(config.unknown_options) << std::endl; } - init_msg << "'" << std::endl; init_msg << std::endl; // Include a list of enabled compile-tiem features, mostly to make debug diff --git a/src/plugin/utils.cpp b/src/plugin/utils.cpp index cd043cf9..651bbaa5 100644 --- a/src/plugin/utils.cpp +++ b/src/plugin/utils.cpp @@ -269,6 +269,17 @@ std::string get_wine_version() { return version_string; } +std::string join_quoted_strings(std::vector& strings) { + bool is_first = true; + std::ostringstream joined_strigns{}; + for (const auto& option : strings) { + joined_strigns << (is_first ? "'" : ", '") << option << "'"; + is_first = false; + } + + return joined_strigns.str(); +} + Configuration load_config_for(const fs::path& yabridge_path) { // First find the closest `yabridge.tmol` file for the plugin, falling back // to default configuration settings if it doesn't exist diff --git a/src/plugin/utils.h b/src/plugin/utils.h index 0deb1cd3..a9d3fb92 100644 --- a/src/plugin/utils.h +++ b/src/plugin/utils.h @@ -166,6 +166,14 @@ boost::filesystem::path get_this_file_location(); */ std::string get_wine_version(); +/** + * Join a vector of strings with commas while wrapping the strings in quotes. + * For example, `join_quoted_strings(std::vector{"string", "another + * string", "also a string"})` outputs `"'string', 'another string', 'also a + * string'"`. This is used to format the initialisation message. + */ +std::string join_quoted_strings(std::vector& strings); + /** * Load the configuration that belongs to a copy of or symlink to * `libyabridge.so`. If no configuration file could be found then this will