22// This file is part of the CPP-AP project (https://github.com/SpectraL519/cpp-ap).
33// Licensed under the MIT License. See the LICENSE file in the project root for full license information.
44
5+ /* *
6+ * @file argument_parser.hpp
7+ * @brief Main library header file. Defines the `argument_parser` class.
8+ */
9+
510#pragma once
611
712#include " argument/default.hpp"
1116#include " detail/concepts.hpp"
1217
1318#include < algorithm>
19+ #include < format>
1420#include < ranges>
1521#include < span>
1622
@@ -68,6 +74,17 @@ class argument_parser {
6874 return *this ;
6975 }
7076
77+ /* *
78+ * @brief Set the verbosity mode.
79+ * @note The default verbosity mode value is `false`.
80+ * @param v The verbosity mode value.
81+ * @return Reference to the argument parser.
82+ */
83+ argument_parser& verbose (const bool v = true ) noexcept {
84+ this ->_verbose = v;
85+ return *this ;
86+ }
87+
7188 /* *
7289 * @brief Set default positional arguments.
7390 * @tparam AR Type of the positional argument discriminator range.
@@ -87,7 +104,7 @@ class argument_parser {
87104 * @return Reference to the argument parser.
88105 */
89106 argument_parser& default_positional_arguments (
90- std::initializer_list<argument::default_positional> arg_discriminator_list
107+ const std::initializer_list<argument::default_positional> arg_discriminator_list
91108 ) noexcept {
92109 return this ->default_positional_arguments <>(arg_discriminator_list);
93110 }
@@ -111,7 +128,7 @@ class argument_parser {
111128 * @return Reference to the argument parser.
112129 */
113130 argument_parser& default_optional_arguments (
114- std::initializer_list<argument::default_optional> arg_discriminator_list
131+ const std::initializer_list<argument::default_optional> arg_discriminator_list
115132 ) noexcept {
116133 return this ->default_optional_arguments <>(arg_discriminator_list);
117134 }
@@ -418,23 +435,41 @@ class argument_parser {
418435
419436 /* *
420437 * @brief Prints the argument parser's details to an output stream.
438+ * @param verbose The verbosity mode value.
421439 * @param os Output stream.
422- * @param parser The argument parser to print.
423- * @return The modified output stream.
424440 */
425- friend std::ostream& operator <<( std::ostream& os, const argument_parser& parser) noexcept {
426- if (parser. _program_name )
427- os << parser. _program_name .value () << std::endl;
441+ void print_config ( const bool verbose, std::ostream& os = std::cout) const noexcept {
442+ if (this -> _program_name )
443+ os << " Program: " << this -> _program_name .value () << std::endl;
428444
429- if (parser._program_description )
430- os << parser._program_description .value () << std::endl;
445+ if (this ->_program_description )
446+ os << " \n "
447+ << std::string (this ->_indent_width , ' ' ) << this ->_program_description .value ()
448+ << std::endl;
431449
432- for (const auto & argument : parser._positional_args )
433- os << " \t " << *argument << std::endl;
450+ if (not this ->_positional_args .empty ()) {
451+ os << " \n Positional arguments:\n " ;
452+ this ->_print (os, this ->_positional_args );
453+ }
434454
435- for (const auto & argument : parser._optional_args )
436- os << " \t " << *argument << std::endl;
455+ if (not this ->_optional_args .empty ()) {
456+ os << " \n Optional arguments: [--,-]\n " ;
457+ this ->_print (os, this ->_optional_args );
458+ }
459+ }
437460
461+ /* *
462+ * @brief Prints the argument parser's details to an output stream.
463+ *
464+ * An `os << parser` operation is equivalent to a `parser.print_config(_verbose, os)` call,
465+ * where `_verbose` is the inner verbosity mode, which can be set with the @ref verbose function.
466+ *
467+ * @param os Output stream.
468+ * @param parser The argument parser to print.
469+ * @return The modified output stream.
470+ */
471+ friend std::ostream& operator <<(std::ostream& os, const argument_parser& parser) noexcept {
472+ parser.print_config (parser._verbose , os);
438473 return os;
439474 }
440475
@@ -547,10 +582,10 @@ class argument_parser {
547582 */
548583 [[nodiscard]] bool _is_flag (const std::string& arg) const noexcept {
549584 if (arg.starts_with (this ->_flag_prefix ))
550- return this ->_is_arg_name_used ({arg.substr (this ->_flag_prefix_length )});
585+ return this ->_is_arg_name_used ({arg.substr (this ->_primary_flag_prefxi_length )});
551586
552587 if (arg.starts_with (this ->_flag_prefix_char ))
553- return this ->_is_arg_name_used ({arg.substr (this ->_flag_prefix_char_length )});
588+ return this ->_is_arg_name_used ({arg.substr (this ->_secondary_flag_prefix_length )});
554589
555590 return false ;
556591 }
@@ -561,9 +596,9 @@ class argument_parser {
561596 */
562597 void _strip_flag_prefix (std::string& arg_flag) const noexcept {
563598 if (arg_flag.starts_with (this ->_flag_prefix ))
564- arg_flag.erase (0 , this ->_flag_prefix_length );
599+ arg_flag.erase (0 , this ->_primary_flag_prefxi_length );
565600 else
566- arg_flag.erase (0 , this ->_flag_prefix_char_length );
601+ arg_flag.erase (0 , this ->_secondary_flag_prefix_length );
567602 }
568603
569604 /* *
@@ -694,20 +729,55 @@ class argument_parser {
694729 return std::nullopt ;
695730 }
696731
732+ /* *
733+ * @brief Print the given argument list to an output stream.
734+ * @param os The output stream to print to.
735+ * @param args The argument list to print.
736+ */
737+ void _print (std::ostream& os, const arg_ptr_list_t & args) const noexcept {
738+ if (this ->_verbose ) {
739+ for (const auto & arg : args)
740+ os << ' \n ' << arg->desc (this ->_verbose ).get (this ->_indent_width ) << ' \n ' ;
741+ }
742+ else {
743+ std::vector<detail::argument_descriptor> descriptors;
744+ descriptors.reserve (args.size ());
745+
746+ for (const auto & arg : args)
747+ descriptors.emplace_back (arg->desc (this ->_verbose ));
748+
749+ std::size_t max_arg_name_length = 0ull ;
750+ for (const auto & desc : descriptors)
751+ max_arg_name_length = std::max (max_arg_name_length, desc.name .length ());
752+
753+ for (const auto & desc : descriptors)
754+ os << ' \n ' << desc.get_basic (this ->_indent_width , max_arg_name_length);
755+
756+ os << ' \n ' ;
757+ }
758+ }
759+
697760 std::optional<std::string> _program_name;
698761 std::optional<std::string> _program_description;
762+ bool _verbose = false ;
699763
700764 arg_ptr_list_t _positional_args;
701765 arg_ptr_list_t _optional_args;
702766
703- static constexpr uint8_t _flag_prefix_char_length = 1u ;
704- static constexpr uint8_t _flag_prefix_length = 2u ;
767+ static constexpr uint8_t _secondary_flag_prefix_length = 1u ;
768+ static constexpr uint8_t _primary_flag_prefxi_length = 2u ;
705769 static constexpr char _flag_prefix_char = ' -' ;
706770 static constexpr std::string _flag_prefix = " --" ;
771+ static constexpr uint8_t _indent_width = 2 ;
707772};
708773
709774namespace detail {
710775
776+ /* *
777+ * @brief Adds a predefined/default positional argument to the parser.
778+ * @param arg_discriminator The default argument discriminator.
779+ * @param arg_parser The argument parser to which the argument will be added.
780+ */
711781inline void add_default_argument (
712782 const argument::default_positional arg_discriminator, argument_parser& arg_parser
713783) noexcept {
@@ -724,6 +794,11 @@ inline void add_default_argument(
724794 }
725795}
726796
797+ /* *
798+ * @brief Adds a predefined/default optional argument to the parser.
799+ * @param arg_discriminator The default argument discriminator.
800+ * @param arg_parser The argument parser to which the argument will be added.
801+ */
727802inline void add_default_argument (
728803 const argument::default_optional arg_discriminator, argument_parser& arg_parser
729804) noexcept {
0 commit comments