diff --git a/config_utilities/include/config_utilities/internal/visitor.h b/config_utilities/include/config_utilities/internal/visitor.h index a63a5ed3..81d739a3 100644 --- a/config_utilities/include/config_utilities/internal/visitor.h +++ b/config_utilities/include/config_utilities/internal/visitor.h @@ -169,13 +169,15 @@ struct Visitor { // Dispatch populating field input info from conversions. template () || isConfig(), bool>::type = true> - static void getFieldInputInfo(const std::string& field_name); + static void getFieldInputInfo(const IntermediateT& intermediate, const std::string& field_name); template () && !isConfig(), bool>::type = true> - static void getFieldInputInfo(const std::string& field_name); + static void getFieldInputInfo(const IntermediateT& intermediate, const std::string& field_name); // Computes the default values for all fields in the meta data. This assumes that the meta data is already created, // and the meta data was created from ConfigT. diff --git a/config_utilities/include/config_utilities/internal/visitor_impl.hpp b/config_utilities/include/config_utilities/internal/visitor_impl.hpp index 2727d8cb..ea2a99d2 100644 --- a/config_utilities/include/config_utilities/internal/visitor_impl.hpp +++ b/config_utilities/include/config_utilities/internal/visitor_impl.hpp @@ -211,14 +211,13 @@ void Visitor::visitField(T& field, const std::string& field_name, const std::str auto intermediate = Conversion::toIntermediate(field, error); if (!error.empty()) { visitor.data.errors.emplace_back(new Warning(field_name, error)); - error.clear(); } Visitor::visitField(intermediate, field_name, unit); // Get type information if requested. if (visitor.mode == Visitor::Mode::kGetInfo) { - Visitor::getFieldInputInfo(field_name); + Visitor::getFieldInputInfo(intermediate, field_name); } } } @@ -457,8 +456,9 @@ void Visitor::getDefaultValues(const ConfigT& config, MetaData& data) { // intentional no-op template () || isConfig(), bool>::type> -void Visitor::getFieldInputInfo(const std::string& field_name) { +void Visitor::getFieldInputInfo(const IntermediateT&, const std::string& field_name) { static_assert(!isConfig() || !hasFieldInputInfo(), "Config types (with declare_config) cannot have field input information!"); @@ -471,14 +471,18 @@ void Visitor::getFieldInputInfo(const std::string& field_name) { visitor.data.errors.emplace_back( new Warning(field_name, "Invalid parsing state! Field info should already exist!")); } else { - visitor.data.field_infos.back().input_info.reset(); // clear field input info for underlying intermediate type + // Default: Create the field input info of the intermediate type. + auto input_info = createFieldInputInfo(); + auto& info = visitor.data.field_infos.back(); + info.input_info = FieldInputInfo::merge(input_info, info.input_info); } } template () && !isConfig(), bool>::type> -void Visitor::getFieldInputInfo(const std::string& field_name) { +void Visitor::getFieldInputInfo(const IntermediateT&, const std::string& field_name) { auto input_info = Conversion::getFieldInputInfo(); auto& visitor = Visitor::instance(); diff --git a/config_utilities/test/tests/conversions.cpp b/config_utilities/test/tests/conversions.cpp index 7643704d..3fde7cdd 100644 --- a/config_utilities/test/tests/conversions.cpp +++ b/config_utilities/test/tests/conversions.cpp @@ -243,8 +243,10 @@ TEST(Conversions, FieldInputInfo) { ConversionStruct without_info; data = internal::Visitor::getInfo(without_info); EXPECT_EQ(data.field_infos.size(), 2); - EXPECT_FALSE(data.field_infos[0].input_info); - EXPECT_FALSE(data.field_infos[1].input_info); + EXPECT_TRUE(data.field_infos[0].input_info); + EXPECT_TRUE(data.field_infos[1].input_info); + EXPECT_EQ(data.field_infos[0].input_info->type, internal::FieldInputInfo::Type::kInt); // num_threads + EXPECT_EQ(data.field_infos[1].input_info->type, internal::FieldInputInfo::Type::kString); // some_character } TEST(Conversions, ConversionDeclareConfigDispatch) { diff --git a/config_utilities_ros/config_utilities_ros/gui/dynamic_config_gui.py b/config_utilities_ros/config_utilities_ros/gui/dynamic_config_gui.py index 1dd4a12b..9c4671fc 100644 --- a/config_utilities_ros/config_utilities_ros/gui/dynamic_config_gui.py +++ b/config_utilities_ros/config_utilities_ros/gui/dynamic_config_gui.py @@ -314,6 +314,10 @@ def parse_rec(config, indent, prefix): prefix_str = "".join([f"{p}{NS_SEP}" for p in prefix]) for field in config["fields"]: if field["type"] == "field": + # Default the input info to just strings if no details are present. + if "input_info" not in field: + field["input_info"] = {"type": "yaml"} + # Data for each field (leaves of the config). field["id"] = f"{prefix_str}{field['name']}" field["indent"] = indent