git.strcat.st

/strcat/minitox.git/ - summarytreelogarchive

subject
make the /help output prettier
commit
7299eb4899a603262414ae6b1d11b730bf02251f
date
2026-04-18T17:22:26Z
message
diff
 minitox.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 74 insertions(+), 3 deletions(-)

diff --git a/minitox.c b/minitox.c
index ab6a77f..3139d86 100644
--- a/minitox.c
+++ b/minitox.c
@@ -102,6 +102,14 @@ struct Command {
     CommandHandler *handler;
 };
 
+struct CommandHelp {
+    const char *name;
+    const char *section;
+    const char *usage;
+    const char *summary;
+    const char *example;
+};
+
 struct GroupUserData {
     uint32_t friend_num;
     uint8_t *cookie;
@@ -1322,6 +1330,45 @@ void command_settitle(int narg, char **args) {
 #define COMMAND_ARGS_REST 10
 #define COMMAND_LENGTH (sizeof(commands)/sizeof(struct Command))
 
+static const char *help_sections[] = {
+    "General",
+    "Profile",
+    "Contacts",
+    "Chat",
+    "Requests",
+    "Groups",
+};
+
+static const struct CommandHelp command_help_info[] = {
+    {"guide", "General", "", "Print the quick start notes.", "/guide"},
+    {"help", "General", "[command]", "Show all commands or help for one.", "/help add"},
+    {"save", "General", "", "Save state to disk now.", "/save"},
+    {"info", "Profile", "[contact_index]", "Show your info or one contact.", "/info 3"},
+    {"setname", "Profile", "<name>", "Change your display name.", "/setname alice"},
+    {"setstmsg", "Profile", "<status_message>", "Change your status message.", "/setstmsg coding"},
+    {"contacts", "Contacts", "", "List friends and groups with indexes.", "/contacts"},
+    {"add", "Contacts", "<toxid> <msg>", "Send a friend request.", "/add <toxid> hi"},
+    {"del", "Contacts", "<contact_index>", "Remove a friend or group.", "/del 4"},
+    {"go", "Chat", "[contact_index]", "Enter chat mode or go back to command mode.", "/go 2"},
+    {"history", "Chat", "[n]", "Show recent lines from this chat.", "/history 30"},
+    {"accept", "Requests", "[request_index]", "List requests or accept one.", "/accept 1"},
+    {"deny", "Requests", "[request_index]", "List requests or deny one.", "/deny 1"},
+    {"invite", "Groups", "<friend_contact_index> [group_contact_index]", "Invite a friend to a group.", "/invite 2"},
+    {"settitle", "Groups", "<group_contact_index> <title>", "Rename a group.", "/settitle 5 friday plan"},
+};
+
+#define HELP_SECTION_COUNT (sizeof(help_sections) / sizeof(help_sections[0]))
+#define HELP_INFO_COUNT (sizeof(command_help_info) / sizeof(command_help_info[0]))
+
+static const struct CommandHelp *find_command_help(const char *name) {
+    for (size_t i = 0; i < HELP_INFO_COUNT; i++) {
+        if (strcmp(command_help_info[i].name, name) == 0) {
+            return &command_help_info[i];
+        }
+    }
+    return NULL;
+}
+
 struct Command commands[] = {
     {
         "guide",
@@ -1332,7 +1379,7 @@ struct Command commands[] = {
     {
         "help",
         "- print this message.",
-        0,
+        0 + COMMAND_ARGS_REST,
         command_help,
     },
     {
@@ -1416,8 +1463,32 @@ struct Command commands[] = {
 };
 
 void command_help(int narg, char **args){
-    for (int i=1;i<COMMAND_LENGTH;i++) {
-        printf("%-16s%s\n", commands[i].name, commands[i].desc);
+    if (narg > 0) {
+        const char *name = args[0];
+        if (name[0] == '/') name++;
+
+        const struct CommandHelp *h = find_command_help(name);
+        if (!h) {
+            WARN("Unknown command: %s", args[0]);
+            return;
+        }
+
+        PRINT("command: /%s", h->name);
+        PRINT("usage:   /%s%s%s", h->name, h->usage[0] ? " " : "", h->usage);
+        PRINT("about:   %s", h->summary);
+        PRINT("example: %s", h->example);
+        return;
+    }
+
+    PRINT("commands (`/help <command>` for details):");
+    for (size_t s = 0; s < HELP_SECTION_COUNT; s++) {
+        PRINT("");
+        PRINT("%s", help_sections[s]);
+        for (size_t i = 0; i < HELP_INFO_COUNT; i++) {
+            const struct CommandHelp *h = &command_help_info[i];
+            if (strcmp(h->section, help_sections[s]) != 0) continue;
+            PRINT("  /%-10s %-30s %s", h->name, h->usage, h->summary);
+        }
     }
 }