Ookii.CommandLine for C++  1.0.0
shell_command.h
Go to the documentation of this file.
1 #ifndef OOKII_SHELL_COMMAND_H_
5 #define OOKII_SHELL_COMMAND_H_
6 
7 #pragma once
8 
9 #include "command_line_builder.h"
11 
12 namespace ookii
13 {
68  template<typename CharType = details::default_char_type, typename Traits = std::char_traits<CharType>, typename Alloc = std::allocator<CharType>>
70  {
71  public:
74 
76  basic_shell_command() = default;
77 
84 
86  virtual ~basic_shell_command() = default;
87 
91  virtual int run() = 0;
92  };
93 
98 
104  template<typename CharType, typename Traits = std::char_traits<CharType>, typename Alloc = std::allocator<CharType>>
106  {
107  public:
113  using string_type = std::basic_string<CharType, Traits, Alloc>;
114 
115  private:
116  using creator = std::function<std::unique_ptr<command_type>(builder_type &)>;
117 
118  public:
119 
125  template<typename T>
127  {
128  auto creator = [](builder_type &builder) -> std::unique_ptr<command_type>
129  {
130  return std::make_unique<T>(builder);
131  };
132 
133  return {name, description, creator};
134  }
135 
139  std::unique_ptr<command_type> create(builder_type &builder) const
140  {
141  return _creator(builder);
142  }
143 
145  const string_type &name() const noexcept
146  {
147  return _name;
148  }
149 
151  const string_type &description() const noexcept
152  {
153  return _description;
154  }
155 
156  private:
158  : _name{name},
159  _description{description},
160  _creator{creator}
161  {
162  }
163 
164  string_type _name;
165  string_type _description;
166  creator _creator;
167  };
168 
190  template<typename CharType = details::default_char_type, typename Traits = std::char_traits<CharType>, typename Alloc = std::allocator<CharType>>
192  {
193  public:
205  using stream_type = std::basic_ostream<CharType, Traits>;
206 
209  static constexpr int error_return_code = 1;
210 
219  basic_shell_command_manager(string_type application_name, bool case_sensitive = false, const std::locale &locale = {})
220  : _commands{string_less{case_sensitive, locale}},
221  _application_name{application_name},
222  _locale{locale},
223  _case_sensitive{case_sensitive}
224  {
225  }
226 
236  template<typename T>
238  {
239  if (name.empty())
240  name = name_helper<T>::name();
241 
242  if (description.empty())
243  description = description_helper<T>::description();
244 
245  auto [it, success] = _commands.emplace(name, info_type::template create<T>(name, description));
246  if (!success)
247  throw std::logic_error("Duplicate command name");
248 
249  return *this;
250  }
251 
255  auto commands() const noexcept
256  {
257  return _commands | std::views::values;
258  }
259 
264  const info_type *get_command(const string_type &name) const
265  {
266  auto it = _commands.find(name);
267  if (it == _commands.end())
268  return nullptr;
269 
270  return &it->second;
271  }
272 
288  template<typename Iterator>
289  std::unique_ptr<command_type> create_command(const string_type &name, Iterator begin, Iterator end, const usage_options_type &options = {}) const
290  {
291  auto info = get_command(name);
292  if (info == nullptr)
293  {
294  write_usage(options);
295  return {};
296  }
297 
298  auto builder = create_parser_builder(*info);
299  auto command = info->create(builder);
300  auto parser = builder.build();
301  if (!parser.parse(begin, end, options))
302  return {};
303 
304  return command;
305  }
306 
321  template<typename Range>
322  std::unique_ptr<command_type> create_command(const string_type &name, Range range, const usage_options_type &options = {}) const
323  {
324  // For ADL
325  using std::begin;
326  using std::end;
327  return create_command(name, begin(range), end(range), options);
328  }
329 
345  template<typename T>
346  std::unique_ptr<command_type> create_command(const string_type &name, std::initializer_list<T> args, const usage_options_type &options = {}) const
347  {
348  return create_command(name, args.begin(), args.end(), options);
349  }
350 
366  template<typename Iterator>
367  std::unique_ptr<command_type> create_command(Iterator begin, Iterator end, const usage_options_type &options = {}) const
368  {
369  if (begin == end)
370  {
371  write_usage(options);
372  return {};
373  }
374 
375  auto &name = *begin;
376  return create_command(name, ++begin, end, options);
377  }
378 
393  template<typename Range>
394  std::unique_ptr<command_type> create_command(Range range, const usage_options_type &options = {}) const
395  {
396  // For ADL
397  using std::begin;
398  using std::end;
399  return create_command(begin(range), end(range), options);
400  }
401 
417  template<typename T>
418  std::unique_ptr<command_type> create_command(std::initializer_list<T> args, const usage_options_type &options = {}) const
419  {
420  return create_command(args.begin(), args.end(), options);
421  }
422 
437  std::unique_ptr<command_type> create_command(int argc, const CharType *const argv[], const usage_options_type &options = {}) const
438  {
439  if (argc < 2)
440  {
441  write_usage(options);
442  return {};
443  }
444 
445  return create_command(argv + 1, argv + argc, options);
446  }
447 
465  template<typename Iterator>
466  int run_command(const string_type &name, Iterator begin, Iterator end, const usage_options_type &options = {}) const
467  {
468  auto command = create_command(name, begin, end, options);
469  if (!command)
470  return error_return_code;
471 
472  return command->run();
473  }
474 
491  template<typename Range>
492  int run_command(const string_type &name, Range range, const usage_options_type &options = {}) const
493  {
494  // For ADL
495  using std::begin;
496  using std::end;
497  return run_command(name, begin(range), end(range), options);
498  }
499 
517  template<typename T>
518  int run_command(const string_type &name, std::initializer_list<T> args, const usage_options_type &options = {}) const
519  {
520  return run_command(name, args.begin(), args.end(), options);
521  }
522 
540  template<typename Iterator>
541  int run_command(Iterator begin, Iterator end, const usage_options_type &options = {}) const
542  {
543  auto command = create_command(begin, end, options);
544  if (!command)
545  return error_return_code;
546 
547  return command->run();
548  }
549 
566  template<typename Range>
567  int run_command(Range range, const usage_options_type &options = {}) const
568  {
569  // For ADL
570  using std::begin;
571  using std::end;
572  return run_command(begin(range), end(range), options);
573  }
574 
592  template<typename T>
593  int run_command(std::initializer_list<T> args, const usage_options_type &options = {}) const
594  {
595  return run_command(args.begin(), args.end(), options);
596  }
597 
614  int run_command(int argc, const CharType *const argv[], const usage_options_type &options = {}) const
615  {
616  auto command = create_command(argc, argv, options);
617  if (!command)
618  return error_return_code;
619 
620  return command->run();
621  }
622 
626  void write_usage(const usage_options_type &options = {}) const
627  {
628  auto &stream = options.output;
629  auto usage = format::ncformat(_locale, options.command_usage_format, _application_name);
630  usage = format::ncformat(_locale, options.usage_prefix_format, usage);
631  stream << usage << std::endl << std::endl;
632  stream << options.available_commands_header << std::endl << std::endl;
633  stream << set_indent(options.command_indent);
634  for (const auto &command : _commands)
635  {
636  stream << reset_indent;
637  stream << format::ncformat(_locale, options.command_format, command.second.name(), command.second.description()) << std::endl;
638  }
639  }
640 
649  {
650  // Include the application name so usage will be correct.
651  string_type full_name = _application_name + static_cast<CharType>(' ') + command.name();
652  builder_type builder{full_name};
653  builder.locale(_locale)
654  .case_sensitive(_case_sensitive)
655  .description(command.description());
656 
657  return builder;
658  }
659 
660  private:
661  template<typename T, typename = void>
662  struct name_helper
663  {
664  static string_type name()
665  {
666  return get_short_type_name<T, CharType, Traits, Alloc>();
667  }
668  };
669 
670  template<typename T>
671  struct name_helper<T, std::void_t<decltype(T::name())>>
672  {
673  static string_type name()
674  {
675  return T::name();
676  }
677  };
678 
679  template<typename T, typename = void>
680  struct description_helper
681  {
682  static string_type description()
683  {
684  return {};
685  }
686  };
687 
688  template<typename T>
689  struct description_helper<T, std::void_t<decltype(T::description())>>
690  {
691  static string_type description()
692  {
693  return T::description();
694  }
695  };
696 
697  std::map<string_type, info_type, string_less> _commands;
698  string_type _application_name;
699  std::locale _locale;
700  bool _case_sensitive;
701  };
702 
707 
708 }
709 
710 #endif
Provides functionality to specify options and arguments to create a new basic_command_line_parser.
Definition: command_line_builder.h:36
Manages registration, creation and invocation of shell commands for an application.
Definition: shell_command.h:192
int run_command(const string_type &name, Range range, const usage_options_type &options={}) const
Creates an instance of the specified command, parsing the specified arguments, and runs the command.
Definition: shell_command.h:492
const info_type * get_command(const string_type &name) const
Gets information about a shell command by name.
Definition: shell_command.h:264
std::unique_ptr< command_type > create_command(std::initializer_list< T > args, const usage_options_type &options={}) const
Creates an instance of a command based on the specified arguments.
Definition: shell_command.h:418
int run_command(const string_type &name, Iterator begin, Iterator end, const usage_options_type &options={}) const
Creates an instance of the specified command, parsing the specified arguments, and runs the command.
Definition: shell_command.h:466
basic_shell_command_manager & add_command(string_type name={}, string_type description={})
Adds a command to the basic_shell_command_manager.
Definition: shell_command.h:237
int run_command(const string_type &name, std::initializer_list< T > args, const usage_options_type &options={}) const
Creates an instance of the specified command, parsing the specified arguments, and runs the command.
Definition: shell_command.h:518
std::unique_ptr< command_type > create_command(Range range, const usage_options_type &options={}) const
Creates an instance of a command based on the specified arguments.
Definition: shell_command.h:394
builder_type create_parser_builder(const info_type &command) const
Creates a basic_parser_builder for a specified command.
Definition: shell_command.h:648
typename info_type::string_type string_type
The concrete string type used.
Definition: shell_command.h:197
std::unique_ptr< command_type > create_command(int argc, const CharType *const argv[], const usage_options_type &options={}) const
Creates an instance of a command based on the specified arguments.
Definition: shell_command.h:437
std::unique_ptr< command_type > create_command(const string_type &name, Iterator begin, Iterator end, const usage_options_type &options={}) const
Creates an instance of the specified command, parsing the specified arguments.
Definition: shell_command.h:289
int run_command(int argc, const CharType *const argv[], const usage_options_type &options={}) const
Creates an instance of a command based onthe specified arguments, and runs the command.
Definition: shell_command.h:614
std::basic_ostream< CharType, Traits > stream_type
The concrete type of output stream used.
Definition: shell_command.h:205
static constexpr int error_return_code
The error exit code used by run_shell_command() if no command name was supplied or thesupplied comman...
Definition: shell_command.h:209
std::unique_ptr< command_type > create_command(const string_type &name, std::initializer_list< T > args, const usage_options_type &options={}) const
Creates an instance of the specified command, parsing the specified arguments.
Definition: shell_command.h:346
std::unique_ptr< command_type > create_command(const string_type &name, Range range, const usage_options_type &options={}) const
Creates an instance of the specified command, parsing the specified arguments.
Definition: shell_command.h:322
int run_command(Range range, const usage_options_type &options={}) const
Creates an instance of a command based onthe specified arguments, and runs the command.
Definition: shell_command.h:567
std::unique_ptr< command_type > create_command(Iterator begin, Iterator end, const usage_options_type &options={}) const
Creates an instance of a command based on the specified arguments.
Definition: shell_command.h:367
typename info_type::builder_type builder_type
The concrete type of basic_parser_builder used.
Definition: shell_command.h:199
void write_usage(const usage_options_type &options={}) const
Writes usage help about the available commands.
Definition: shell_command.h:626
int run_command(std::initializer_list< T > args, const usage_options_type &options={}) const
Creates an instance of a command based onthe specified arguments, and runs the command.
Definition: shell_command.h:593
int run_command(Iterator begin, Iterator end, const usage_options_type &options={}) const
Creates an instance of a command based onthe specified arguments, and runs the command.
Definition: shell_command.h:541
auto commands() const noexcept
Gets a view of all the commands.
Definition: shell_command.h:255
typename info_type::command_type command_type
The concrete type of basic_shell_command used.
Definition: shell_command.h:201
basic_shell_command_manager(string_type application_name, bool case_sensitive=false, const std::locale &locale={})
Initializes a new instance of the basic_shell_command_manager class.
Definition: shell_command.h:219
Provides options for how to format usage help for applications using shell commands.
Definition: shell_command_usage_options.h:30
Abstract base class for all shell commands.
Definition: shell_command.h:70
virtual ~basic_shell_command()=default
Default destructor.
basic_shell_command()=default
Initializes a new instance of the basic_shell_command class.
basic_parser_builder< CharType, Traits, Alloc > builder_type
The concrete type of basic_parser_builder used.
Definition: shell_command.h:73
virtual int run()=0
Runs the command, after argument parsing was successful.
basic_shell_command(builder_type &)
Initializes a new instance of the basic_shell_command class.
Definition: shell_command.h:83
Provides information about a shell command.
Definition: shell_command.h:106
typename command_type::builder_type builder_type
The concrete type of basic_parser_builder used.
Definition: shell_command.h:111
basic_shell_command< CharType, Traits, Alloc > command_type
The concrete type of basic_shell_command used.
Definition: shell_command.h:109
static shell_command_info create(string_type name, string_type description)
Creates a shell_command_info instance for the specified type.
Definition: shell_command.h:126
const string_type & description() const noexcept
Gets the description of the shell command.
Definition: shell_command.h:151
std::basic_string< CharType, Traits, Alloc > string_type
The concrete string type used.
Definition: shell_command.h:113
std::unique_ptr< command_type > create(builder_type &builder) const
Creates an instance of the shell command type.
Definition: shell_command.h:139
const string_type & name() const noexcept
Gets the name of the shell command.
Definition: shell_command.h:145
Provides the ookii::basic_parser_builder class.
std::string ncformat(const std::locale &loc, std::string_view format, Args &&... args)
Helper to format using a non-const format string without needing to explicitly construct a format_arg...
Definition: format_helper.h:55
Namespace containing the core Ookii.CommandLine.Cpp types.
Definition: command_line_argument.h:16
std::basic_ostream< CharType, Traits > & reset_indent(std::basic_ostream< CharType, Traits > &stream)
IO manipulator that lets the next line start at the beginning of the line, without indenting it.
Definition: line_wrapping_stream.h:515
details::set_indent_helper set_indent(size_t indent)
IO manipulator that changes the number of spaces that each line is indented with for a line wrapping ...
Definition: line_wrapping_stream.h:493
Provides the ookii::shell_command_usage_options class.
A version of the std::less predicate for strings that supports case insensitive comparison.
Definition: string_helper.h:23