Ookii.CommandLine for C++  2.0.0
subcommand.h
Go to the documentation of this file.
1 #ifndef OOKII_SUBCOMMAND_H_
5 #define OOKII_SUBCOMMAND_H_
6 
7 #pragma once
8 
9 #include "command_line_builder.h"
10 #include <span>
11 
12 namespace ookii
13 {
67  template<typename CharType, typename Traits = std::char_traits<CharType>, typename Alloc = std::allocator<CharType>>
69  {
70  public:
73 
75  basic_command() = default;
76 
83 
85  virtual ~basic_command() = default;
86 
90  virtual int run() = 0;
91  };
92 
97 
114  template<typename CharType, typename Traits = std::char_traits<CharType>, typename Alloc = std::allocator<CharType>>
115  class basic_command_with_custom_parsing : public basic_command<CharType, Traits, Alloc>
116  {
117  public:
122 
128  virtual bool parse(std::span<const CharType *const> args, const command_manager_type &manager, usage_writer_type *usage) = 0;
129  };
130 
135 
141  template<typename CharType, typename Traits = std::char_traits<CharType>, typename Alloc = std::allocator<CharType>>
143  {
144  public:
152  using string_type = std::basic_string<CharType, Traits, Alloc>;
154  using creator = std::function<std::unique_ptr<command_type>(builder_type *)>;
155 
156  public:
157 
165  : _name{name},
166  _description{description},
167  _creator{creator},
168  _use_custom_argument_parsing{use_custom_argument_parsing}
169  {
170  }
171 
177  template<typename T, std::enable_if_t<!std::is_base_of_v<command_with_custom_parsing_type, T>, int> = 0>
179  {
180  auto creator = [](builder_type *builder) -> std::unique_ptr<command_type>
181  {
182  return std::make_unique<T>(*builder);
183  };
184 
185  return {name, description, creator};
186  }
187 
194  template<typename T, std::enable_if_t<std::is_base_of_v<command_with_custom_parsing_type, T>, int> = 0>
196  {
197  auto creator = [](builder_type *) -> std::unique_ptr<command_type>
198  {
199  return std::make_unique<T>();
200  };
201 
202  return {name, description, creator, true};
203  }
204 
211  std::unique_ptr<command_type> create(builder_type &builder) const
212  {
213  if (_use_custom_argument_parsing)
214  {
215  return {};
216  }
217 
218  return _creator(&builder);
219  }
220 
227  std::unique_ptr<command_type> create_custom_parsing() const
228  {
229  if (!_use_custom_argument_parsing)
230  {
231  return {};
232  }
233 
234  return _creator(nullptr);
235  }
236 
240  bool use_custom_argument_parsing() const noexcept
241  {
242  return _use_custom_argument_parsing;
243  }
244 
246  const string_type &name() const noexcept
247  {
248  return _name;
249  }
250 
252  const string_type &description() const noexcept
253  {
254  return _description;
255  }
256 
257  private:
258  string_type _name;
259  string_type _description;
260  creator _creator;
261  bool _use_custom_argument_parsing{};
262  };
263 
264  namespace details
265  {
266  template<typename CharType, typename Traits, typename Alloc>
267  class version_command : public basic_command<CharType, Traits, Alloc>
268  {
269  public:
270  using base_type = basic_command<CharType, Traits, Alloc>;
271  using builder_type = typename base_type::builder_type;
272 
273  version_command(builder_type &builder, typename builder_type::version_function function)
274  : base_type{builder},
275  _function{function}
276  {
277  }
278 
279  virtual int run() override
280  {
281  _function();
282  return 0;
283  }
284 
285  private:
286  typename builder_type::version_function _function;
287  };
288  }
289 
311  template<typename CharType = details::default_char_type, typename Traits = std::char_traits<CharType>, typename Alloc = std::allocator<CharType>>
313  {
314  public:
328  using stream_type = std::basic_ostream<CharType, Traits>;
330  using configure_function = std::function<void(builder_type&)>;
332  using version_function = std::function<void()>;
335 
349  const string_provider_type *string_provider = nullptr)
350  : _commands{string_less{case_sensitive, locale}},
351  _application_name{application_name},
352  _locale{locale},
353  _string_provider{string_provider},
354  _case_sensitive{case_sensitive}
355  {
356  if (_string_provider == nullptr)
357  {
358  _string_provider = &string_provider_type::get_default();
359  }
360  }
361 
366  {
367  _description = description;
368  return *this;
369  }
370 
372  const string_type &description() const
373  {
374  return _description;
375  }
376 
392  {
393  _common_help_argument = name_with_prefix;
394  return *this;
395  }
396 
400  {
401  return _common_help_argument;
402  }
403 
417  {
418  _configure_function = function;
419  return *this;
420  }
421 
432  template<typename T>
434  {
435  if (name.empty())
436  name = name_helper<T>::name();
437 
438  if (description.empty())
439  description = description_helper<T>::description();
440 
441  auto [it, success] = _commands.emplace(name, info_type::template create<T>(name, description));
442  if (!success)
443  throw std::logic_error("Duplicate command name");
444 
445  return *this;
446  }
447 
460  {
461  auto creator = [function = std::move(function)](builder_type *builder) -> std::unique_ptr<command_type>
462  {
463  return std::make_unique<details::version_command<CharType, Traits, Alloc>>(*builder, function);
464  };
465 
466  auto name = _string_provider->automatic_version_command_name();
467  auto description = _string_provider->automatic_version_description();
468  auto [it, success] = _commands.emplace(name, info_type{name, description, creator});
469  if (!success)
470  throw std::logic_error("Duplicate command name");
471 
472  return *this;
473  }
474 
475 #if defined(_WIN32) || defined(DOXYGEN)
492  {
493  return add_version_command(details::show_win32_version<CharType>);
494  }
495 #endif
496 
497 
499  auto commands() const noexcept
500  {
501  return details::range_filter<const info_type &, typename std::map<string_type, info_type, string_less>::const_iterator>{
502  _commands.begin(),
503  _commands.end(),
504  [](const auto &a) -> auto&
505  {
506  return a.second;
507  },
508  {}
509  };
510  }
511 
513  const string_type &application_name() const noexcept
514  {
515  return _application_name;
516  }
517 
519  const std::locale &locale() const noexcept
520  {
521  return _locale;
522  }
523 
527  const string_provider_type &string_provider() const noexcept
528  {
529  return *_string_provider;
530  }
531 
537  bool case_sensitive() const noexcept
538  {
539  return _case_sensitive;
540  }
541 
546  const info_type *get_command(const string_type &name) const
547  {
548  auto it = _commands.find(name);
549  if (it == _commands.end())
550  return nullptr;
551 
552  return &it->second;
553  }
554 
569  std::unique_ptr<command_type> create_command(int argc, const CharType *const argv[], usage_writer_type *usage = nullptr) const
570  {
571  if (argc < 2)
572  {
573  write_usage(usage);
574  return {};
575  }
576 
577  std::span args{argv, static_cast<size_t>(argc)};
578  return create_command(argv[1], args.subspan(2), usage);
579  }
580 
594  std::unique_ptr<command_type> create_command(std::span<const CharType *const> args, usage_writer_type *usage = nullptr) const
595  {
596  if (args.size() < 1)
597  {
598  write_usage(usage);
599  return {};
600  }
601 
602  return create_command(args[0], args.subspan(1), usage);
603  }
604 
619  std::unique_ptr<command_type> create_command(const string_type &name, std::span<const CharType *const> args, usage_writer_type *usage = nullptr) const
620  {
621  auto info = get_command(name);
622  if (info == nullptr)
623  {
624  write_usage(usage);
625  return {};
626  }
627 
628  std::unique_ptr<command_type> command;
629  if (info->use_custom_argument_parsing())
630  {
631  command = info->create_custom_parsing();
632  auto custom_command = static_cast<command_with_custom_parsing_type*>(command.get());
633  if (!custom_command->parse(args, *this, usage))
634  return {};
635  }
636  else
637  {
638  auto builder = create_parser_builder(*info);
639  command = info->create(builder);
640  auto parser = builder.build();
641  if (!parser.parse(args, usage))
642  return {};
643  }
644 
645  return command;
646  }
647 
664  std::optional<int> run_command(int argc, const CharType *const argv[], usage_writer_type *usage = nullptr) const
665  {
666  auto command = create_command(argc, argv, usage);
667  if (!command)
668  return {};
669 
670  return command->run();
671  }
672 
688  std::optional<int> run_command(std::span<const CharType *const> args, usage_writer_type *usage = nullptr) const
689  {
690  auto command = create_command(args, usage);
691  if (!command)
692  return {};
693 
694  return command->run();
695  }
696 
713  std::optional<int> run_command(const string_type &name, std::span<const CharType *const> args, usage_writer_type *usage = nullptr) const
714  {
715  auto command = create_command(name, args, usage);
716  if (!command)
717  return {};
718 
719  return command->run();
720  }
721 
725  void write_usage(usage_writer_type *usage = nullptr) const
726  {
727  if (usage == nullptr)
728  {
730  }
731  else
732  {
733  usage->write_command_list_usage(*this);
734  }
735  }
736 
745  {
746  // Include the application name so usage will be correct.
747  string_type full_name = _application_name + static_cast<CharType>(' ') + command.name();
748  builder_type builder{full_name, _string_provider};
749  builder.locale(_locale)
750  .case_sensitive(_case_sensitive)
751  .description(command.description());
752 
753  if (_configure_function)
754  {
755  _configure_function(builder);
756  }
757 
758  return builder;
759  }
760 
761  private:
762  template<typename T, typename = void>
763  struct name_helper
764  {
765  static string_type name()
766  {
767  return get_short_type_name<T, CharType, Traits, Alloc>();
768  }
769  };
770 
771  template<typename T>
772  struct name_helper<T, std::void_t<decltype(T::name())>>
773  {
774  static string_type name()
775  {
776  return T::name();
777  }
778  };
779 
780  template<typename T, typename = void>
781  struct description_helper
782  {
783  static string_type description()
784  {
785  return {};
786  }
787  };
788 
789  template<typename T>
790  struct description_helper<T, std::void_t<decltype(T::description())>>
791  {
792  static string_type description()
793  {
794  return T::description();
795  }
796  };
797 
798  std::map<string_type, info_type, string_less> _commands;
799  string_type _application_name;
800  string_type _description;
801  string_type _common_help_argument;
802  std::locale _locale;
803  configure_function _configure_function;
804  const string_provider_type *_string_provider;
805  bool _case_sensitive;
806  };
807 
812 
813 }
814 
815 #endif
Manages registration, creation and invocation of subcommands for an application.
Definition: subcommand.h:313
bool case_sensitive() const noexcept
Gets a value that indicates whether command names are case sensitive.
Definition: subcommand.h:537
typename info_type::builder_type builder_type
The concrete type of basic_parser_builder used.
Definition: subcommand.h:320
std::unique_ptr< command_type > create_command(std::span< const CharType *const > args, usage_writer_type *usage=nullptr) const
Creates an instance of a command based on the specified arguments.
Definition: subcommand.h:594
basic_command_manager & configure_parser(configure_function function)
Sets a function that can be used to configure parser options for every command.
Definition: subcommand.h:416
basic_command_manager & description(string_type description)
Sets a description that will be shown before the command list usage help.
Definition: subcommand.h:365
const string_type & description() const
Gets the description that will be shown before the command list usage help.
Definition: subcommand.h:372
basic_localized_string_provider< CharType, Traits, Alloc > string_provider_type
The specialized type of basic_localized_string_provider used.
Definition: subcommand.h:334
basic_command_manager & common_help_argument(string_type name_with_prefix)
Sets the name of a help argument, including prefix, that is used by all subcommands.
Definition: subcommand.h:391
basic_command_manager & add_version_command(version_function function)
Adds the standard version command.
Definition: subcommand.h:459
void write_usage(usage_writer_type *usage=nullptr) const
Writes usage help about the available commands.
Definition: subcommand.h:725
basic_command_manager & add_win32_version_command()
Adds the standard version argument, using version information from the VERSIONINFO resource.
Definition: subcommand.h:491
const string_provider_type & string_provider() const noexcept
Gets the basic_localized_string_provider implementation used to get strings for error messages etc.
Definition: subcommand.h:527
std::optional< int > run_command(int argc, const CharType *const argv[], usage_writer_type *usage=nullptr) const
Creates an instance of a command based on the specified arguments, and runs the command.
Definition: subcommand.h:664
const string_type & common_help_argument() const
Gets the name of a help argument, including prefix, that is used by all subcommands.
Definition: subcommand.h:399
std::optional< int > run_command(std::span< const CharType *const > args, usage_writer_type *usage=nullptr) const
Creates an instance of a command based on the specified arguments, and runs the command.
Definition: subcommand.h:688
typename info_type::command_with_custom_parsing_type command_with_custom_parsing_type
The concrete type of basic_command_with_custom_parsing used.
Definition: subcommand.h:324
auto commands() const noexcept
Gets a view of all the commands.
Definition: subcommand.h:499
std::unique_ptr< command_type > create_command(const string_type &name, std::span< const CharType *const > args, usage_writer_type *usage=nullptr) const
Creates an instance of a command based on the specified arguments.
Definition: subcommand.h:619
typename info_type::string_type string_type
The concrete string type used.
Definition: subcommand.h:318
const string_type & application_name() const noexcept
Gets the name of the application containing the command.
Definition: subcommand.h:513
builder_type create_parser_builder(const info_type &command) const
Creates a basic_parser_builder for a specified command.
Definition: subcommand.h:744
std::function< void(builder_type &)> configure_function
The type of a function used to configure parser options for every command.
Definition: subcommand.h:330
std::function< void()> version_function
The type of a function that displays version information.
Definition: subcommand.h:332
std::optional< int > run_command(const string_type &name, std::span< const CharType *const > args, usage_writer_type *usage=nullptr) const
Creates an instance of a command based on the specified arguments, and runs the command.
Definition: subcommand.h:713
const std::locale & locale() const noexcept
Gets the locale used to parse argument values and to format strings.
Definition: subcommand.h:519
std::basic_ostream< CharType, Traits > stream_type
The concrete type of output stream used.
Definition: subcommand.h:328
std::unique_ptr< command_type > create_command(int argc, const CharType *const argv[], usage_writer_type *usage=nullptr) const
Creates an instance of a command based on the specified arguments.
Definition: subcommand.h:569
typename info_type::command_type command_type
The concrete type of basic_command used.
Definition: subcommand.h:322
basic_command_manager & add_command(string_type name={}, string_type description={})
Adds a command to the basic_command_manager.
Definition: subcommand.h:433
const info_type * get_command(const string_type &name) const
Gets information about a subcommand by name.
Definition: subcommand.h:546
basic_command_manager(string_type application_name, bool case_sensitive=false, const std::locale &locale={}, const string_provider_type *string_provider=nullptr)
Initializes a new instance of the basic_command_manager class.
Definition: subcommand.h:348
Abstract base class for subcommands that do their own argument parsing.
Definition: subcommand.h:116
virtual bool parse(std::span< const CharType *const > args, const command_manager_type &manager, usage_writer_type *usage)=0
Parses the arguments for the command.
Abstract base class for all subcommands.
Definition: subcommand.h:69
virtual ~basic_command()=default
Default destructor.
virtual int run()=0
Runs the command, after argument parsing was successful.
basic_command(builder_type &)
Initializes a new instance of the basic_command class.
Definition: subcommand.h:82
basic_command()=default
Initializes a new instance of the basic_command class.
basic_parser_builder< CharType, Traits, Alloc > builder_type
The concrete type of basic_parser_builder used.
Definition: subcommand.h:72
Provides custom localized strings.
Definition: localized_string_provider.h:30
static basic_localized_string_provider & get_default() noexcept
Gets a default instance of the basic_localized_string_provider.
Definition: localized_string_provider.h:38
virtual string_type automatic_version_command_name() const
Gets the name of the version command created by basic_command_manager::add_version_command().
Definition: localized_string_provider.h:135
virtual string_type automatic_version_description() const
Gets the description of the version argument created by basic_parser_builder::add_version_argument().
Definition: localized_string_provider.h:142
Provides functionality to specify options and arguments to create a new basic_command_line_parser.
Definition: command_line_builder.h:73
Creates usage help for the basic_command_line_parser and basic_command_manager classes.
Definition: usage_writer.h:99
virtual void write_command_list_usage(const command_manager_type &manager)
Creates usage help for the specified command manager.
Definition: usage_writer.h:377
Provides information about a subcommand.
Definition: subcommand.h:143
std::unique_ptr< command_type > create(builder_type &builder) const
Creates an instance of the subcommand type.
Definition: subcommand.h:211
typename command_type::builder_type builder_type
The concrete type of basic_parser_builder used.
Definition: subcommand.h:150
basic_command< CharType, Traits, Alloc > command_type
The concrete type of basic_command used.
Definition: subcommand.h:146
static command_info create(string_type name, string_type description)
Creates a command_info instance for the specified command type.
Definition: subcommand.h:178
const string_type & description() const noexcept
Gets the description of the subcommand.
Definition: subcommand.h:252
const string_type & name() const noexcept
Gets the name of the subcommand.
Definition: subcommand.h:246
std::function< std::unique_ptr< command_type >(builder_type *)> creator
The type of a function that instantiates a subcommand.
Definition: subcommand.h:154
std::basic_string< CharType, Traits, Alloc > string_type
The concrete string type used.
Definition: subcommand.h:152
command_info(string_type name, string_type description, creator creator, bool use_custom_argument_parsing=false)
Initializes a new instance of the command_info class.
Definition: subcommand.h:164
std::unique_ptr< command_type > create_custom_parsing() const
Creates an instance of the subcommand type for commands that use custom argument parsing.
Definition: subcommand.h:227
bool use_custom_argument_parsing() const noexcept
Gets a value that indicates whether the command uses custom argument parsing.
Definition: subcommand.h:240
basic_command_with_custom_parsing< CharType, Traits, Alloc > command_with_custom_parsing_type
The concrete type of basic_command_with_custom_parsing used.
Definition: subcommand.h:148
Provides the ookii::basic_parser_builder class.
Namespace containing the core Ookii.CommandLine.Cpp types.
Definition: command_line_argument.h:16
basic_command< char > command
Typedef for basic_command using char as the character type.
Definition: subcommand.h:94
@ success
The operation was successful.
A version of the std::less predicate for strings that supports case insensitive comparison.
Definition: string_helper.h:30