@@ -734,17 +734,20 @@ class format_help_base : public format_base
734734 }
735735#endif
736736
737- auto positional_subrange =
738- std::ranges::partition (synopsis_elements, std::logical_not{}, &synopsis_element::is_positional);
737+ std::ranges::stable_sort (synopsis_elements, std::ranges::less{}, &synopsis_element::type);
738+ auto const pivot = std::ranges::lower_bound (synopsis_elements,
739+ synopsis_element::option_type::positional,
740+ std::ranges::less{},
741+ &synopsis_element::type);
739742
740- for (auto it = synopsis_elements.begin (); it != positional_subrange. begin () ; ++it)
743+ for (auto it = synopsis_elements.begin (); it != pivot ; ++it)
741744 {
742745 synopsis_line += " " + it->option_str ;
743746 }
744- if (! std::ranges::empty (positional_subrange ))
747+ if (pivot != synopsis_elements. end ( ))
745748 {
746749 synopsis_line += " [\\ fB--\\ fP]" ;
747- for (auto it = positional_subrange. begin () ; it != positional_subrange .end (); ++it)
750+ for (auto it = pivot ; it != synopsis_elements .end (); ++it)
748751 {
749752 synopsis_line += " " + it->option_str ;
750753 }
@@ -766,8 +769,15 @@ class format_help_base : public format_base
766769 // !\brief Structure to store synopsis element information.
767770 struct synopsis_element
768771 {
769- std::string option_str; // !< The formatted option string.
770- bool is_positional{false }; // !< Whether it's a positional argument.
772+ // !\brief Kinds of options.
773+ enum class option_type : uint8_t
774+ {
775+ flag, // !< Option is a flag.
776+ option, // !< Option is a option with argument.
777+ positional // !< Option is a positional option.
778+ };
779+ std::string option_str; // !< The formatted option string.
780+ option_type type; // !< Type of the option.
771781 };
772782
773783 // !\brief Stores elements for automatic synopsis generation.
@@ -796,6 +806,7 @@ class format_help_base : public format_base
796806 * \param[in] type_str The type string for the option value.
797807 * \param[in] required Whether the option is required.
798808 * \param[in] is_list Whether it's a list of arguments.
809+ * \sa https://pubs.opengroup.org/onlinepubs/9699919799
799810 */
800811 void store_synopsis_option (detail::id_pair const & id,
801812 std::string const & type_str,
@@ -818,20 +829,23 @@ class format_help_base : public format_base
818829 opt_str = opt_str + " [" + opt_str + " ]..." ;
819830 }
820831
821- synopsis_elements.push_back ({opt_str, false });
832+ synopsis_elements.push_back ({std::move ( opt_str), synopsis_element::option_type::option });
822833 }
823834
824835 /* !\brief Stores flag information for synopsis generation.
825836 * \param[in] id A sharg::detail::id_pair encapsulating both short and long id.
837+ * \sa https://pubs.opengroup.org/onlinepubs/9699919799
826838 */
827839 void store_synopsis_flag (detail::id_pair const & id)
828840 {
829- synopsis_elements.push_back ({prep_id_for_help (id, true ), false });
841+ std::string flag_str = " [" + prep_id_for_help (id, true ) + " ]" ;
842+ synopsis_elements.push_back ({std::move (flag_str), synopsis_element::option_type::flag});
830843 }
831844
832845 /* !\brief Stores positional argument information for synopsis generation.
833846 * \param[in] type_str The type string for the positional argument.
834847 * \param[in] is_list Whether it's a list of arguments.
848+ * \sa https://pubs.opengroup.org/onlinepubs/9699919799
835849 */
836850 void store_synopsis_positional (std::string const & type_str, bool const is_list)
837851 {
@@ -840,7 +854,7 @@ class format_help_base : public format_base
840854 if (is_list)
841855 pos_str += " ..." ;
842856
843- synopsis_elements.push_back ({pos_str, true });
857+ synopsis_elements.push_back ({std::move ( pos_str), synopsis_element::option_type::positional });
844858 }
845859
846860 /* !\brief Adds a function object to parser_set_up_calls **if** the annotation in `config` does not prevent it.
0 commit comments