@@ -137,7 +137,7 @@ class format_base
137
137
*
138
138
* \details Special characters considered are `"`, `\`, `&`, `<` and `>`.
139
139
*/
140
- std::string escape_special_xml_chars (std::string const & original)
140
+ static std::string escape_special_xml_chars (std::string const & original)
141
141
{
142
142
std::string escaped;
143
143
escaped.reserve (original.size ()); // will be at least as long
@@ -183,6 +183,62 @@ class format_base
183
183
184
184
return tmp;
185
185
}
186
+
187
+ /* !\brief Returns the default message for the help page.
188
+ * \tparam option_type The type of the option.
189
+ * \tparam default_type The type of the default value.
190
+ * \param[in] option The option to get the default message for.
191
+ * \param[in] value The default value to get the default message for.
192
+ * \returns The default message for the help page (" Default: <default-value>. ").
193
+ * \details
194
+ * `value` is either `config.default_message`, or the same as `option`.
195
+ * If the `option_type` is a std::string or std::filesystem::path, the value is quoted.
196
+ * If the `option_type` is a container of std::string or std::filesystem::path, each individual value is quoted;
197
+ * if a `config.default_message` is provided, it will not be quoted.
198
+ */
199
+ template <typename option_type, typename default_type>
200
+ static std::string get_default_message (option_type const & SHARG_DOXYGEN_ONLY (option), default_type const & value)
201
+ {
202
+ static_assert (std::same_as<option_type, default_type> || std::same_as<default_type, std::string>);
203
+
204
+ std::stringstream message{};
205
+ message << " Default: " ;
206
+
207
+ if constexpr (detail::is_container_option<option_type>)
208
+ {
209
+ // If we have a list of strings, we want to quote each string.
210
+ if constexpr (std::same_as<std::ranges::range_value_t <default_type>, std::string>)
211
+ {
212
+ auto view = std::views::transform (value,
213
+ [](auto const & val)
214
+ {
215
+ return std::quoted (val);
216
+ });
217
+ message << detail::to_string (view);
218
+ }
219
+ else // Otherwise we just print the list or the default_message without quotes.
220
+ {
221
+ message << detail::to_string (value);
222
+ }
223
+ }
224
+ else
225
+ {
226
+ static constexpr bool option_is_string = std::same_as<option_type, std::string>;
227
+ static constexpr bool option_is_path = std::same_as<option_type, std::filesystem::path>;
228
+ static constexpr bool value_is_string = std::same_as<default_type, std::string>;
229
+
230
+ // Quote: std::string (from value + default_message), and std::filesystem::path (default_message).
231
+ // std::filesystem::path is quoted by the STL's operator<< in detail::to_string.
232
+ static constexpr bool needs_string_quote = option_is_string || (option_is_path && value_is_string);
233
+
234
+ if constexpr (needs_string_quote)
235
+ message << std::quoted (value);
236
+ else
237
+ message << detail::to_string (value);
238
+ }
239
+
240
+ return message.str ();
241
+ }
186
242
};
187
243
188
244
/* !\brief The format that contains all helper functions needed in all formats for
@@ -227,12 +283,14 @@ class format_help_base : public format_base
227
283
{
228
284
std::string id = prep_id_for_help (config.short_id , config.long_id ) + " " + option_type_and_list_info (value);
229
285
std::string info{config.description };
286
+
230
287
if (config.default_message .empty ())
231
- info += ((config.required ) ? std::string{" " } : detail::to_string ( " Default: " , value, " . " ));
288
+ info += ((config.required ) ? std::string{} : get_default_message ( value, value ));
232
289
else
233
- info += detail::to_string ( " Default: " , config.default_message , " . " );
290
+ info += get_default_message (value , config.default_message );
234
291
235
- info += config.validator .get_help_page_message ();
292
+ if (auto const & validator_message = config.validator .get_help_page_message (); !validator_message.empty ())
293
+ info += " . " + validator_message;
236
294
237
295
store_help_page_element (
238
296
[this , id, info]()
@@ -262,20 +320,41 @@ class format_help_base : public format_base
262
320
template <typename option_type, typename validator_t >
263
321
void add_positional_option (option_type & value, config<validator_t > const & config)
264
322
{
323
+ // a list at the end may be empty and thus have a default value
324
+ auto positional_default_message = [&value]() -> std::string
325
+ {
326
+ if constexpr (detail::is_container_option<option_type>)
327
+ {
328
+ return get_default_message (value, value);
329
+ }
330
+ else
331
+ {
332
+ (void )value; // Silence unused variable warning.
333
+ return {};
334
+ }
335
+ };
336
+
337
+ auto positional_validator_message = [&config]() -> std::string
338
+ {
339
+ if (auto const & validator_message = config.validator .get_help_page_message (); !validator_message.empty ())
340
+ return " . " + validator_message;
341
+ else
342
+ return {};
343
+ };
344
+
265
345
positional_option_calls.push_back (
266
- [this , &value, description = config.description , validator = config.validator ]()
346
+ [this ,
347
+ &value,
348
+ default_message = positional_default_message (),
349
+ validator_message = positional_validator_message (),
350
+ description = config.description ]()
267
351
{
268
352
++positional_option_count;
269
353
derived_t ().print_list_item (detail::to_string (" \\ fBARGUMENT-" ,
270
354
positional_option_count,
271
355
" \\ fP " ,
272
356
option_type_and_list_info (value)),
273
- description +
274
- // a list at the end may be empty and thus have a default value
275
- ((detail::is_container_option<option_type>)
276
- ? detail::to_string (" Default: " , value, " . " )
277
- : std::string{" " })
278
- + validator.get_help_page_message ());
357
+ description + default_message + validator_message);
279
358
});
280
359
}
281
360
@@ -343,7 +422,7 @@ class format_help_base : public format_base
343
422
+ detail::supported_exports + " ." );
344
423
if (version_check_dev_decision == update_notifications::on)
345
424
derived_t ().print_list_item (" \\ fB--version-check\\ fP (bool)" ,
346
- " Whether to check for the newest app version. Default: true. " );
425
+ " Whether to check for the newest app version. Default: true" );
347
426
348
427
if (!meta.examples .empty ())
349
428
{
0 commit comments