aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorStefan Boberg <[email protected]>2026-03-30 17:57:56 +0200
committerStefan Boberg <[email protected]>2026-03-30 17:57:56 +0200
commit6058329192d2fa41e662c4e954995a53ef3edb19 (patch)
treefdf1c98585a32e0098f445ee13f3f8f25d12a728 /src
parentAdd interactive help command to zen CLI (diff)
downloadzen-6058329192d2fa41e662c4e954995a53ef3edb19.tar.xz
zen-6058329192d2fa41e662c4e954995a53ef3edb19.zip
Show global options and subcommands in help command pages
- Include global zen options (debug, verbose, logging, tracing, sentry) below each command's own help text - For commands with subcommands (e.g. hub, exec), show a summary listing of all subcommands followed by detailed per-subcommand options - Add SubCommands() accessor to ZenCmdWithSubCommands - Pass global cxxopts::Options to HelpCommand via SetGlobalOptions()
Diffstat (limited to 'src')
-rw-r--r--src/zen/cmds/help_cmd.cpp71
-rw-r--r--src/zen/cmds/help_cmd.h4
-rw-r--r--src/zen/zen.cpp2
-rw-r--r--src/zen/zen.h2
4 files changed, 77 insertions, 2 deletions
diff --git a/src/zen/cmds/help_cmd.cpp b/src/zen/cmds/help_cmd.cpp
index 82c260a0e..98961abcc 100644
--- a/src/zen/cmds/help_cmd.cpp
+++ b/src/zen/cmds/help_cmd.cpp
@@ -79,6 +79,73 @@ PrintCommandList(std::span<const CommandInfo> Commands)
}
}
+// Build the global options help text, filtering out hidden groups
+static std::string
+GlobalOptionsHelpText(cxxopts::Options* GlobalOptions)
+{
+ if (GlobalOptions == nullptr)
+ {
+ return {};
+ }
+
+ std::vector<std::string> Groups = GlobalOptions->groups();
+ Groups.erase(std::remove(Groups.begin(), Groups.end(), std::string("__hidden__")), Groups.end());
+ GlobalOptions->set_width(TuiConsoleColumns(80));
+ return GlobalOptions->help(Groups);
+}
+
+// Build the full help text for a command, including subcommands and global options
+std::string
+HelpCommand::BuildFullHelpText(const CommandInfo& Cmd) const
+{
+ std::string Text = Cmd.Cmd->HelpText();
+
+ // If this command has subcommands, append their listing and individual options
+ ZenCmdWithSubCommands* CmdWithSubs = dynamic_cast<ZenCmdWithSubCommands*>(Cmd.Cmd);
+ if (CmdWithSubs != nullptr)
+ {
+ auto SubCmds = CmdWithSubs->SubCommands();
+ if (!SubCmds.empty())
+ {
+ // Subcommand summary listing
+ size_t MaxNameLen = 0;
+ for (ZenSubCmdBase* Sub : SubCmds)
+ {
+ MaxNameLen = std::max(MaxNameLen, Sub->SubOptions().program().size());
+ }
+
+ Text += "\nSubcommands:\n";
+ for (ZenSubCmdBase* Sub : SubCmds)
+ {
+ Text += fmt::format(" {:<{}} {}\n", Sub->SubOptions().program(), MaxNameLen, Sub->Description());
+ }
+
+ // Detailed options for each subcommand
+ for (ZenSubCmdBase* Sub : SubCmds)
+ {
+ std::vector<std::string> Groups = Sub->SubOptions().groups();
+ Groups.erase(std::remove(Groups.begin(), Groups.end(), std::string("__hidden__")), Groups.end());
+ Sub->SubOptions().set_width(TuiConsoleColumns(80));
+ std::string SubHelp = Sub->SubOptions().help(Groups);
+ if (!SubHelp.empty())
+ {
+ Text += "\n";
+ Text += SubHelp;
+ }
+ }
+ }
+ }
+
+ std::string GlobalHelp = GlobalOptionsHelpText(m_GlobalOptions);
+ if (!GlobalHelp.empty())
+ {
+ Text += "\n\nGlobal Options:\n";
+ Text += GlobalHelp;
+ }
+
+ return Text;
+}
+
void
HelpCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** argv)
{
@@ -103,7 +170,7 @@ HelpCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** argv)
{
if (StrCaseCompare(m_CommandName.c_str(), Cmd.CmdName) == 0)
{
- std::string HelpText = Cmd.Cmd->HelpText();
+ std::string HelpText = BuildFullHelpText(Cmd);
if (IsTuiAvailable())
{
@@ -175,7 +242,7 @@ HelpCommand::Run(const ZenCliOptions& GlobalOptions, int argc, char** argv)
continue; // Category header selected, ignore
}
- std::string HelpText = SelectedCmd->Cmd->HelpText();
+ std::string HelpText = BuildFullHelpText(*SelectedCmd);
std::vector<std::string> Lines = SplitLines(HelpText);
std::string Title = fmt::format("zen {} -- {}", SelectedCmd->CmdName, SelectedCmd->CmdSummary);
TuiPager(Title, Lines);
diff --git a/src/zen/cmds/help_cmd.h b/src/zen/cmds/help_cmd.h
index 2bccd9db1..29018e803 100644
--- a/src/zen/cmds/help_cmd.h
+++ b/src/zen/cmds/help_cmd.h
@@ -18,14 +18,18 @@ public:
~HelpCommand();
void SetCommands(std::span<const CommandInfo> Commands) { m_Commands = Commands; }
+ void SetGlobalOptions(cxxopts::Options* GlobalOptions) { m_GlobalOptions = GlobalOptions; }
virtual void Run(const ZenCliOptions& GlobalOptions, int argc, char** argv) override;
virtual cxxopts::Options& Options() override { return m_Options; }
virtual ZenCmdCategory& CommandCategory() const override { return g_UtilitiesCategory; }
private:
+ std::string BuildFullHelpText(const CommandInfo& Cmd) const;
+
cxxopts::Options m_Options{Name, Description};
std::span<const CommandInfo> m_Commands;
+ cxxopts::Options* m_GlobalOptions = nullptr;
std::string m_CommandName;
bool m_List = false;
};
diff --git a/src/zen/zen.cpp b/src/zen/zen.cpp
index 67c2e6c77..87d83cc77 100644
--- a/src/zen/zen.cpp
+++ b/src/zen/zen.cpp
@@ -855,6 +855,8 @@ main(int argc, char** argv)
Options.parse_positional({"command"});
+ HelpCmd.SetGlobalOptions(&Options);
+
const bool IsNullInvoke = (argc == 1); // If no arguments are passed we want to print usage information
try
diff --git a/src/zen/zen.h b/src/zen/zen.h
index b24b61369..80178910a 100644
--- a/src/zen/zen.h
+++ b/src/zen/zen.h
@@ -120,6 +120,8 @@ class ZenCmdWithSubCommands : public ZenCmdBase
public:
void Run(const ZenCliOptions& GlobalOptions, int argc, char** argv) final;
+ std::span<ZenSubCmdBase* const> SubCommands() const { return m_SubCommands; }
+
protected:
void AddSubCommand(ZenSubCmdBase& SubCmd);
virtual bool OnParentOptionsParsed(const ZenCliOptions& GlobalOptions);