@@ -5,12 +5,14 @@ import std;
55export import :options;
66export import :parse;
77
8- namespace cmdline {
8+ namespace mcpplibs :: cmdline {
99
1010class SubcommandBuilder ;
11+ class SubcommandArgBuilder ;
1112class OptBuilder ;
1213class ArgBuilder ;
1314
15+ export using Args = std::vector<std::string>;
1416export using detail::Arg;
1517export using detail::Option;
1618export using detail::OptionValue;
@@ -414,6 +416,7 @@ private:
414416
415417// 链式子命令构建器:.subcommand("add").description("...").action(...) 或 .subcommand("remove")...
416418class SubcommandBuilder {
419+ friend class SubcommandArgBuilder ;
417420public:
418421 SubcommandBuilder (App* parent, App sub_app) : parent_(parent), sub_(std::move(sub_app)) {}
419422 SubcommandBuilder (SubcommandBuilder&& other) noexcept
@@ -438,11 +441,18 @@ public:
438441 SubcommandBuilder& author (std::string_view author_str) { (void )sub_.author (author_str); return *this ; }
439442 SubcommandBuilder& description (std::string_view desc) { (void )sub_.description (desc); return *this ; }
440443 SubcommandBuilder& arg (Arg argument) { (void )sub_.arg (std::move (argument)); return *this ; }
441- ArgBuilder arg (std::string_view name);
444+ SubcommandArgBuilder arg (std::string_view name);
442445 SubcommandBuilder& option (Option opt) { (void )sub_.option (std::move (opt)); return *this ; }
443446 OptBuilder option (std::string_view name);
447+
448+ // Commits this subcommand to the parent App and returns App& to enable further chaining.
444449 template <typename Fn>
445- SubcommandBuilder& action (Fn&& fn) { (void )sub_.action (std::forward<Fn>(fn)); return *this ; }
450+ App& action (Fn&& fn) {
451+ (void )sub_.action (std::forward<Fn>(fn));
452+ App* p = parent_;
453+ commit ();
454+ return *p;
455+ }
446456
447457 SubcommandBuilder& subcommand (std::string_view name) {
448458 commit ();
@@ -469,6 +479,42 @@ private:
469479 bool committed_ = false ;
470480};
471481
482+ // 子命令内参数链式构建器:保持在 SubcommandBuilder 上下文中,使整条链能正确返回根 App&。
483+ class SubcommandArgBuilder {
484+ public:
485+ SubcommandArgBuilder (SubcommandArgBuilder&& other) noexcept
486+ : sb_(other.sb_), arg_(std::move(other.arg_)), committed_(other.committed_) {
487+ other.sb_ = nullptr ;
488+ }
489+ SubcommandArgBuilder& operator =(SubcommandArgBuilder&&) = delete ;
490+ SubcommandArgBuilder (const SubcommandArgBuilder&) = delete ;
491+ SubcommandArgBuilder& operator =(const SubcommandArgBuilder&) = delete ;
492+ ~SubcommandArgBuilder () { commit (); }
493+
494+ SubcommandArgBuilder& required (bool r = true ) { (void )arg_.required (r); return *this ; }
495+ SubcommandArgBuilder& help (std::string_view h) { (void )arg_.help (h); return *this ; }
496+ SubcommandArgBuilder& default_value (std::string_view v) { (void )arg_.default_value (v); return *this ; }
497+
498+ SubcommandArgBuilder arg (std::string_view name) { commit (); return sb_->arg (name); }
499+
500+ template <typename Fn>
501+ App& action (Fn&& fn) { commit (); return sb_->action (std::forward<Fn>(fn)); }
502+
503+ private:
504+ SubcommandArgBuilder (SubcommandBuilder* sb, Arg a) : sb_(sb), arg_(std::move(a)) {}
505+ void commit () {
506+ if (sb_ && !committed_) {
507+ (void )sb_->sub_ .arg (std::move (arg_));
508+ committed_ = true ;
509+ }
510+ }
511+ SubcommandBuilder* sb_ = nullptr ;
512+ Arg arg_;
513+ bool committed_ = false ;
514+
515+ friend class SubcommandBuilder ;
516+ };
517+
472518inline SubcommandBuilder App::subcommand (std::string_view name) {
473519 return SubcommandBuilder (this , App (name));
474520}
@@ -493,8 +539,8 @@ inline SubcommandBuilder ArgBuilder::subcommand(std::string_view name) {
493539inline OptBuilder SubcommandBuilder::option (std::string_view name) {
494540 return OptBuilder (&sub_, Option (name));
495541}
496- inline ArgBuilder SubcommandBuilder::arg (std::string_view name) {
497- return ArgBuilder (&sub_ , Arg (name));
542+ inline SubcommandArgBuilder SubcommandBuilder::arg (std::string_view name) {
543+ return SubcommandArgBuilder ( this , Arg (name));
498544}
499545
500- } // namespace cmdline
546+ } // namespace mcpplibs:: cmdline
0 commit comments