mirror of
https://codeberg.org/redict/redict.git
synced 2025-01-22 08:08:53 -05:00
redis-cli generates command help tables from the results of COMMAND (#10043)
This is a followup to #9656 and implements the following step mentioned in that PR: * When possible, extract all the help and completion tips from COMMAND DOCS (Redis 7.0 and up) * If COMMAND DOCS fails, use the static help.h compiled into redis-cli. * Supplement additional command names from COMMAND (pre-Redis 7.0) The last step is needed to add module command and other non-standard commands. This PR does not change the interactive hinting mechanism, which still uses only the param strings to provide somewhat unreliable and inconsistent command hints (see #8084). That task is left for a future PR. Co-authored-by: Oran Agra <oran@redislabs.com>
This commit is contained in:
parent
e662f6835e
commit
5b17909c4f
395
src/redis-cli.c
395
src/redis-cli.c
@ -58,7 +58,7 @@
|
||||
#include "adlist.h"
|
||||
#include "zmalloc.h"
|
||||
#include "linenoise.h"
|
||||
#include "help.h"
|
||||
#include "help.h" /* Used for backwards-compatibility with pre-7.0 servers that don't support COMMAND DOCS. */
|
||||
#include "anet.h"
|
||||
#include "ae.h"
|
||||
#include "cli_common.h"
|
||||
@ -167,13 +167,21 @@ int *spectrum_palette;
|
||||
int spectrum_palette_size;
|
||||
|
||||
/* Dict Helpers */
|
||||
|
||||
static uint64_t dictSdsHash(const void *key);
|
||||
static int dictSdsKeyCompare(dict *d, const void *key1,
|
||||
const void *key2);
|
||||
static void dictSdsDestructor(dict *d, void *val);
|
||||
static void dictListDestructor(dict *d, void *val);
|
||||
|
||||
/* Command documentation info used for help output */
|
||||
struct commandDocs {
|
||||
char *name;
|
||||
char *params; /* A string describing the syntax of the command arguments. */
|
||||
char *summary;
|
||||
char *group;
|
||||
char *since;
|
||||
};
|
||||
|
||||
/* Cluster Manager Command Info */
|
||||
typedef struct clusterManagerCommand {
|
||||
char *name;
|
||||
@ -398,11 +406,11 @@ typedef struct {
|
||||
sds full;
|
||||
|
||||
/* Only used for help on commands */
|
||||
struct commandHelp *org;
|
||||
struct commandDocs org;
|
||||
} helpEntry;
|
||||
|
||||
static helpEntry *helpEntries;
|
||||
static int helpEntriesLen;
|
||||
static helpEntry *helpEntries = NULL;
|
||||
static int helpEntriesLen = 0;
|
||||
|
||||
static sds cliVersion(void) {
|
||||
sds version;
|
||||
@ -418,7 +426,8 @@ static sds cliVersion(void) {
|
||||
return version;
|
||||
}
|
||||
|
||||
static void cliInitHelp(void) {
|
||||
/* For backwards compatibility with pre-7.0 servers. Initializes command help. */
|
||||
static void cliOldInitHelp(void) {
|
||||
int commandslen = sizeof(commandHelp)/sizeof(struct commandHelp);
|
||||
int groupslen = sizeof(commandGroups)/sizeof(char*);
|
||||
int i, len, pos = 0;
|
||||
@ -433,7 +442,11 @@ static void cliInitHelp(void) {
|
||||
tmp.argv[0] = sdscatprintf(sdsempty(),"@%s",commandGroups[i]);
|
||||
tmp.full = tmp.argv[0];
|
||||
tmp.type = CLI_HELP_GROUP;
|
||||
tmp.org = NULL;
|
||||
tmp.org.name = NULL;
|
||||
tmp.org.params = NULL;
|
||||
tmp.org.summary = NULL;
|
||||
tmp.org.since = NULL;
|
||||
tmp.org.group = NULL;
|
||||
helpEntries[pos++] = tmp;
|
||||
}
|
||||
|
||||
@ -441,17 +454,22 @@ static void cliInitHelp(void) {
|
||||
tmp.argv = sdssplitargs(commandHelp[i].name,&tmp.argc);
|
||||
tmp.full = sdsnew(commandHelp[i].name);
|
||||
tmp.type = CLI_HELP_COMMAND;
|
||||
tmp.org = &commandHelp[i];
|
||||
tmp.org.name = commandHelp[i].name;
|
||||
tmp.org.params = commandHelp[i].params;
|
||||
tmp.org.summary = commandHelp[i].summary;
|
||||
tmp.org.since = commandHelp[i].since;
|
||||
tmp.org.group = commandGroups[commandHelp[i].group];
|
||||
helpEntries[pos++] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
/* cliInitHelp() setups the helpEntries array with the command and group
|
||||
/* For backwards compatibility with pre-7.0 servers.
|
||||
* cliOldInitHelp() setups the helpEntries array with the command and group
|
||||
* names from the help.h file. However the Redis instance we are connecting
|
||||
* to may support more commands, so this function integrates the previous
|
||||
* entries with additional entries obtained using the COMMAND command
|
||||
* available in recent versions of Redis. */
|
||||
static void cliIntegrateHelp(void) {
|
||||
static void cliOldIntegrateHelp(void) {
|
||||
if (cliConnect(CC_QUIET) == REDIS_ERR) return;
|
||||
|
||||
redisReply *reply = redisCommand(context, "COMMAND");
|
||||
@ -486,33 +504,334 @@ static void cliIntegrateHelp(void) {
|
||||
new->type = CLI_HELP_COMMAND;
|
||||
sdstoupper(new->argv[0]);
|
||||
|
||||
struct commandHelp *ch = zmalloc(sizeof(*ch));
|
||||
ch->name = new->argv[0];
|
||||
ch->params = sdsempty();
|
||||
new->org.name = new->argv[0];
|
||||
new->org.params = sdsempty();
|
||||
int args = llabs(entry->element[1]->integer);
|
||||
args--; /* Remove the command name itself. */
|
||||
if (entry->element[3]->integer == 1) {
|
||||
ch->params = sdscat(ch->params,"key ");
|
||||
new->org.params = sdscat(new->org.params,"key ");
|
||||
args--;
|
||||
}
|
||||
while(args-- > 0) ch->params = sdscat(ch->params,"arg ");
|
||||
while(args-- > 0) new->org.params = sdscat(new->org.params,"arg ");
|
||||
if (entry->element[1]->integer < 0)
|
||||
ch->params = sdscat(ch->params,"...options...");
|
||||
ch->summary = "Help not available";
|
||||
ch->group = 0;
|
||||
ch->since = "not known";
|
||||
new->org = ch;
|
||||
new->org.params = sdscat(new->org.params,"...options...");
|
||||
new->org.summary = "Help not available";
|
||||
new->org.since = "Not known";
|
||||
new->org.group = commandGroups[0];
|
||||
}
|
||||
freeReplyObject(reply);
|
||||
}
|
||||
|
||||
/* Concatenate a string to an sds string, but if it's empty substitute double quote marks. */
|
||||
static sds sdscat_orempty(sds params, char *value) {
|
||||
if (value[0] == '\0') {
|
||||
return sdscat(params, "\"\"");
|
||||
}
|
||||
return sdscat(params, value);
|
||||
}
|
||||
|
||||
static sds cliAddArgument(sds params, redisReply *argMap);
|
||||
|
||||
/* Concatenate a list of arguments to the parameter string, separated by a separator string. */
|
||||
static sds cliConcatArguments(sds params, redisReply *arguments, char *separator) {
|
||||
for (size_t j = 0; j < arguments->elements; j++) {
|
||||
params = cliAddArgument(params, arguments->element[j]);
|
||||
if (j != arguments->elements - 1) {
|
||||
params = sdscat(params, separator);
|
||||
}
|
||||
}
|
||||
return params;
|
||||
}
|
||||
|
||||
/* Add an argument to the parameter string. */
|
||||
static sds cliAddArgument(sds params, redisReply *argMap) {
|
||||
char *name = NULL;
|
||||
char *type = NULL;
|
||||
int optional = 0;
|
||||
int multiple = 0;
|
||||
int multipleToken = 0;
|
||||
redisReply *arguments = NULL;
|
||||
sds tokenPart = sdsempty();
|
||||
sds repeatPart = sdsempty();
|
||||
|
||||
/* First read the fields describing the argument. */
|
||||
if (argMap->type != REDIS_REPLY_MAP && argMap->type != REDIS_REPLY_ARRAY) {
|
||||
return params;
|
||||
}
|
||||
for (size_t i = 0; i < argMap->elements; i += 2) {
|
||||
assert(argMap->element[i]->type == REDIS_REPLY_STRING);
|
||||
char *key = argMap->element[i]->str;
|
||||
if (!strcmp(key, "name")) {
|
||||
assert(argMap->element[i + 1]->type == REDIS_REPLY_STRING);
|
||||
name = argMap->element[i + 1]->str;
|
||||
} else if (!strcmp(key, "token")) {
|
||||
assert(argMap->element[i + 1]->type == REDIS_REPLY_STRING);
|
||||
char *token = argMap->element[i + 1]->str;
|
||||
tokenPart = sdscat_orempty(tokenPart, token);
|
||||
} else if (!strcmp(key, "type")) {
|
||||
assert(argMap->element[i + 1]->type == REDIS_REPLY_STRING);
|
||||
type = argMap->element[i + 1]->str;
|
||||
} else if (!strcmp(key, "arguments")) {
|
||||
arguments = argMap->element[i + 1];
|
||||
} else if (!strcmp(key, "flags")) {
|
||||
redisReply *flags = argMap->element[i + 1];
|
||||
assert(flags->type == REDIS_REPLY_SET || flags->type == REDIS_REPLY_ARRAY);
|
||||
for (size_t j = 0; j < flags->elements; j++) {
|
||||
assert(flags->element[j]->type == REDIS_REPLY_STATUS);
|
||||
char *flag = flags->element[j]->str;
|
||||
if (!strcmp(flag, "optional")) {
|
||||
optional = 1;
|
||||
} else if (!strcmp(flag, "multiple")) {
|
||||
multiple = 1;
|
||||
} else if (!strcmp(flag, "multiple_token")) {
|
||||
multipleToken = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Then build the "repeating part" of the argument string. */
|
||||
if (!strcmp(type, "key") ||
|
||||
!strcmp(type, "string") ||
|
||||
!strcmp(type, "integer") ||
|
||||
!strcmp(type, "double") ||
|
||||
!strcmp(type, "pattern") ||
|
||||
!strcmp(type, "unix-time") ||
|
||||
!strcmp(type, "token"))
|
||||
{
|
||||
repeatPart = sdscat_orempty(repeatPart, name);
|
||||
} else if (!strcmp(type, "oneof")) {
|
||||
repeatPart = cliConcatArguments(repeatPart, arguments, "|");
|
||||
} else if (!strcmp(type, "block")) {
|
||||
repeatPart = cliConcatArguments(repeatPart, arguments, " ");
|
||||
} else if (strcmp(type, "pure-token") != 0) {
|
||||
fprintf(stderr, "Unknown type '%s' set for argument '%s'\n", type, name);
|
||||
}
|
||||
|
||||
/* Finally, build the parameter string. */
|
||||
if (tokenPart[0] != '\0' && strcmp(type, "pure-token") != 0) {
|
||||
tokenPart = sdscat(tokenPart, " ");
|
||||
}
|
||||
if (optional) {
|
||||
params = sdscat(params, "[");
|
||||
}
|
||||
params = sdscat(params, tokenPart);
|
||||
params = sdscat(params, repeatPart);
|
||||
if (multiple) {
|
||||
params = sdscat(params, " [");
|
||||
if (multipleToken) {
|
||||
params = sdscat(params, tokenPart);
|
||||
}
|
||||
params = sdscat(params, repeatPart);
|
||||
params = sdscat(params, " ...]");
|
||||
}
|
||||
if (optional) {
|
||||
params = sdscat(params, "]");
|
||||
}
|
||||
sdsfree(tokenPart);
|
||||
sdsfree(repeatPart);
|
||||
return params;
|
||||
}
|
||||
|
||||
/* Fill in the fields of a help entry for the command/subcommand name. */
|
||||
static void cliFillInCommandHelpEntry(helpEntry *help, char *cmdname, char *subcommandname) {
|
||||
help->argc = subcommandname ? 2 : 1;
|
||||
help->argv = zmalloc(sizeof(sds) * help->argc);
|
||||
help->argv[0] = sdsnew(cmdname);
|
||||
sdstoupper(help->argv[0]);
|
||||
if (subcommandname) {
|
||||
/* Subcommand name is two words separated by a pipe character. */
|
||||
help->argv[1] = sdsnew(strchr(subcommandname, '|') + 1);
|
||||
sdstoupper(help->argv[1]);
|
||||
}
|
||||
sds fullname = sdsnew(help->argv[0]);
|
||||
if (subcommandname) {
|
||||
fullname = sdscat(fullname, " ");
|
||||
fullname = sdscat(fullname, help->argv[1]);
|
||||
}
|
||||
help->full = fullname;
|
||||
help->type = CLI_HELP_COMMAND;
|
||||
|
||||
help->org.name = help->full;
|
||||
help->org.params = sdsempty();
|
||||
help->org.since = NULL;
|
||||
}
|
||||
|
||||
/* Initialize a command help entry for the command/subcommand described in 'specs'.
|
||||
* 'next' points to the next help entry to be filled in.
|
||||
* 'groups' is a set of command group names to be filled in.
|
||||
* Returns a pointer to the next available position in the help entries table.
|
||||
* If the command has subcommands, this is called recursively for the subcommands.
|
||||
*/
|
||||
static helpEntry *cliInitCommandHelpEntry(char *cmdname, char *subcommandname,
|
||||
helpEntry *next, redisReply *specs,
|
||||
dict *groups) {
|
||||
helpEntry *help = next++;
|
||||
cliFillInCommandHelpEntry(help, cmdname, subcommandname);
|
||||
|
||||
assert(specs->type == REDIS_REPLY_MAP || specs->type == REDIS_REPLY_ARRAY);
|
||||
for (size_t j = 0; j < specs->elements; j += 2) {
|
||||
assert(specs->element[j]->type == REDIS_REPLY_STRING);
|
||||
char *key = specs->element[j]->str;
|
||||
if (!strcmp(key, "summary")) {
|
||||
redisReply *reply = specs->element[j + 1];
|
||||
assert(reply->type == REDIS_REPLY_STRING);
|
||||
help->org.summary = sdsnew(reply->str);
|
||||
} else if (!strcmp(key, "since")) {
|
||||
redisReply *reply = specs->element[j + 1];
|
||||
assert(reply->type == REDIS_REPLY_STRING);
|
||||
help->org.since = sdsnew(reply->str);
|
||||
} else if (!strcmp(key, "group")) {
|
||||
redisReply *reply = specs->element[j + 1];
|
||||
assert(reply->type == REDIS_REPLY_STRING);
|
||||
help->org.group = sdsnew(reply->str);
|
||||
sds group = sdsdup(help->org.group);
|
||||
if (dictAdd(groups, group, NULL) != DICT_OK) {
|
||||
sdsfree(group);
|
||||
}
|
||||
} else if (!strcmp(key, "arguments")) {
|
||||
redisReply *args = specs->element[j + 1];
|
||||
assert(args->type == REDIS_REPLY_ARRAY);
|
||||
help->org.params = cliConcatArguments(help->org.params, args, " ");
|
||||
} else if (!strcmp(key, "subcommands")) {
|
||||
redisReply *subcommands = specs->element[j + 1];
|
||||
assert(subcommands->type == REDIS_REPLY_MAP || subcommands->type == REDIS_REPLY_ARRAY);
|
||||
for (size_t i = 0; i < subcommands->elements; i += 2) {
|
||||
assert(subcommands->element[i]->type == REDIS_REPLY_STRING);
|
||||
char *subcommandname = subcommands->element[i]->str;
|
||||
redisReply *subcommand = subcommands->element[i + 1];
|
||||
assert(subcommand->type == REDIS_REPLY_MAP || subcommand->type == REDIS_REPLY_ARRAY);
|
||||
next = cliInitCommandHelpEntry(cmdname, subcommandname, next, subcommand, groups);
|
||||
}
|
||||
}
|
||||
}
|
||||
return next;
|
||||
}
|
||||
|
||||
/* Returns the total number of commands and subcommands in the command docs table. */
|
||||
static size_t cliCountCommands(redisReply* commandTable) {
|
||||
size_t numCommands = commandTable->elements / 2;
|
||||
|
||||
/* The command docs table maps command names to a map of their specs. */
|
||||
for (size_t i = 0; i < commandTable->elements; i += 2) {
|
||||
assert(commandTable->element[i]->type == REDIS_REPLY_STRING); /* Command name. */
|
||||
assert(commandTable->element[i + 1]->type == REDIS_REPLY_MAP ||
|
||||
commandTable->element[i + 1]->type == REDIS_REPLY_ARRAY);
|
||||
redisReply *map = commandTable->element[i + 1];
|
||||
for (size_t j = 0; j < map->elements; j += 2) {
|
||||
assert(map->element[j]->type == REDIS_REPLY_STRING);
|
||||
char *key = map->element[j]->str;
|
||||
if (!strcmp(key, "subcommands")) {
|
||||
redisReply *subcommands = map->element[j + 1];
|
||||
assert(subcommands->type == REDIS_REPLY_MAP || subcommands->type == REDIS_REPLY_ARRAY);
|
||||
numCommands += subcommands->elements / 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
return numCommands;
|
||||
}
|
||||
|
||||
/* Comparator for sorting help table entries. */
|
||||
int helpEntryCompare(const void *entry1, const void *entry2) {
|
||||
helpEntry *i1 = (helpEntry *)entry1;
|
||||
helpEntry *i2 = (helpEntry *)entry2;
|
||||
return strcmp(i1->full, i2->full);
|
||||
}
|
||||
|
||||
/* Initializes command help entries for command groups.
|
||||
* Called after the command help entries have already been filled in.
|
||||
* Extends the help table with new entries for the command groups.
|
||||
*/
|
||||
void cliInitGroupHelpEntries(dict *groups) {
|
||||
dictIterator *iter = dictGetIterator(groups);
|
||||
dictEntry *entry;
|
||||
helpEntry tmp;
|
||||
|
||||
int numGroups = dictSize(groups);
|
||||
int pos = helpEntriesLen;
|
||||
helpEntriesLen += numGroups;
|
||||
helpEntries = zrealloc(helpEntries, sizeof(helpEntry)*helpEntriesLen);
|
||||
|
||||
for (entry = dictNext(iter); entry != NULL; entry = dictNext(iter)) {
|
||||
tmp.argc = 1;
|
||||
tmp.argv = zmalloc(sizeof(sds));
|
||||
tmp.argv[0] = sdscatprintf(sdsempty(),"@%s",(char *)entry->key);
|
||||
tmp.full = tmp.argv[0];
|
||||
tmp.type = CLI_HELP_GROUP;
|
||||
tmp.org.name = NULL;
|
||||
tmp.org.params = NULL;
|
||||
tmp.org.summary = NULL;
|
||||
tmp.org.since = NULL;
|
||||
tmp.org.group = NULL;
|
||||
helpEntries[pos++] = tmp;
|
||||
}
|
||||
dictReleaseIterator(iter);
|
||||
}
|
||||
|
||||
/* Initializes help entries for all commands in the COMMAND DOCS reply. */
|
||||
void cliInitCommandHelpEntries(redisReply *commandTable, dict *groups) {
|
||||
helpEntry *next = helpEntries;
|
||||
for (size_t i = 0; i < commandTable->elements; i += 2) {
|
||||
assert(commandTable->element[i]->type == REDIS_REPLY_STRING);
|
||||
char *cmdname = commandTable->element[i]->str;
|
||||
|
||||
assert(commandTable->element[i + 1]->type == REDIS_REPLY_MAP ||
|
||||
commandTable->element[i + 1]->type == REDIS_REPLY_ARRAY);
|
||||
redisReply *cmdspecs = commandTable->element[i + 1];
|
||||
next = cliInitCommandHelpEntry(cmdname, NULL, next, cmdspecs, groups);
|
||||
}
|
||||
}
|
||||
|
||||
/* cliInitHelp() sets up the helpEntries array with the command and group
|
||||
* names and command descriptions obtained using the COMMAND DOCS command.
|
||||
*/
|
||||
static void cliInitHelp(void) {
|
||||
/* Dict type for a set of strings, used to collect names of command groups. */
|
||||
dictType groupsdt = {
|
||||
dictSdsHash, /* hash function */
|
||||
NULL, /* key dup */
|
||||
NULL, /* val dup */
|
||||
dictSdsKeyCompare, /* key compare */
|
||||
dictSdsDestructor, /* key destructor */
|
||||
NULL, /* val destructor */
|
||||
NULL /* allow to expand */
|
||||
};
|
||||
redisReply *commandTable;
|
||||
dict *groups;
|
||||
|
||||
if (cliConnect(CC_QUIET) == REDIS_ERR) return;
|
||||
commandTable = redisCommand(context, "COMMAND DOCS");
|
||||
if (commandTable == NULL || commandTable->type == REDIS_REPLY_ERROR) {
|
||||
/* New COMMAND DOCS subcommand not supported - generate help from old help.h data instead. */
|
||||
freeReplyObject(commandTable);
|
||||
cliOldInitHelp();
|
||||
cliOldIntegrateHelp();
|
||||
return;
|
||||
};
|
||||
if (commandTable->type != REDIS_REPLY_MAP && commandTable->type != REDIS_REPLY_ARRAY) return;
|
||||
|
||||
/* Scan the array reported by COMMAND DOCS and fill in the entries */
|
||||
helpEntriesLen = cliCountCommands(commandTable);
|
||||
helpEntries = zmalloc(sizeof(helpEntry)*helpEntriesLen);
|
||||
|
||||
groups = dictCreate(&groupsdt);
|
||||
cliInitCommandHelpEntries(commandTable, groups);
|
||||
cliInitGroupHelpEntries(groups);
|
||||
|
||||
qsort(helpEntries, helpEntriesLen, sizeof(helpEntry), helpEntryCompare);
|
||||
freeReplyObject(commandTable);
|
||||
dictRelease(groups);
|
||||
}
|
||||
|
||||
/* Output command help to stdout. */
|
||||
static void cliOutputCommandHelp(struct commandHelp *help, int group) {
|
||||
static void cliOutputCommandHelp(struct commandDocs *help, int group) {
|
||||
printf("\r\n \x1b[1m%s\x1b[0m \x1b[90m%s\x1b[0m\r\n", help->name, help->params);
|
||||
printf(" \x1b[33msummary:\x1b[0m %s\r\n", help->summary);
|
||||
printf(" \x1b[33msince:\x1b[0m %s\r\n", help->since);
|
||||
if (help->since != NULL) {
|
||||
printf(" \x1b[33msince:\x1b[0m %s\r\n", help->since);
|
||||
}
|
||||
if (group) {
|
||||
printf(" \x1b[33mgroup:\x1b[0m %s\r\n", commandGroups[help->group]);
|
||||
printf(" \x1b[33mgroup:\x1b[0m %s\r\n", help->group);
|
||||
}
|
||||
}
|
||||
|
||||
@ -538,22 +857,16 @@ static void cliOutputGenericHelp(void) {
|
||||
|
||||
/* Output all command help, filtering by group or command name. */
|
||||
static void cliOutputHelp(int argc, char **argv) {
|
||||
int i, j, len;
|
||||
int group = -1;
|
||||
int i, j;
|
||||
char *group = NULL;
|
||||
helpEntry *entry;
|
||||
struct commandHelp *help;
|
||||
struct commandDocs *help;
|
||||
|
||||
if (argc == 0) {
|
||||
cliOutputGenericHelp();
|
||||
return;
|
||||
} else if (argc > 0 && argv[0][0] == '@') {
|
||||
len = sizeof(commandGroups)/sizeof(char*);
|
||||
for (i = 0; i < len; i++) {
|
||||
if (strcasecmp(argv[0]+1,commandGroups[i]) == 0) {
|
||||
group = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
group = argv[0]+1;
|
||||
}
|
||||
|
||||
assert(argc > 0);
|
||||
@ -561,8 +874,8 @@ static void cliOutputHelp(int argc, char **argv) {
|
||||
entry = &helpEntries[i];
|
||||
if (entry->type != CLI_HELP_COMMAND) continue;
|
||||
|
||||
help = entry->org;
|
||||
if (group == -1) {
|
||||
help = &entry->org;
|
||||
if (group == NULL) {
|
||||
/* Compare all arguments */
|
||||
if (argc <= entry->argc) {
|
||||
for (j = 0; j < argc; j++) {
|
||||
@ -572,10 +885,8 @@ static void cliOutputHelp(int argc, char **argv) {
|
||||
cliOutputCommandHelp(help,1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (group == help->group) {
|
||||
cliOutputCommandHelp(help,0);
|
||||
}
|
||||
} else if (strcasecmp(group, help->group) == 0) {
|
||||
cliOutputCommandHelp(help,0);
|
||||
}
|
||||
}
|
||||
printf("\r\n");
|
||||
@ -649,7 +960,7 @@ static char *hintsCallback(const char *buf, int *color, int *bold) {
|
||||
if (entry) {
|
||||
*color = 90;
|
||||
*bold = 0;
|
||||
sds hint = sdsnew(entry->org->params);
|
||||
sds hint = sdsnew(entry->org.params);
|
||||
|
||||
/* Remove arguments from the returned hint to show only the
|
||||
* ones the user did not yet type. */
|
||||
@ -2229,10 +2540,8 @@ static void repl(void) {
|
||||
int argc;
|
||||
sds *argv;
|
||||
|
||||
/* Initialize the help and, if possible, use the COMMAND command in order
|
||||
* to retrieve missing entries. */
|
||||
/* Initialize the help using the results of the COMMAND command. */
|
||||
cliInitHelp();
|
||||
cliIntegrateHelp();
|
||||
|
||||
config.interactive = 1;
|
||||
linenoiseSetMultiLine(1);
|
||||
|
@ -647,7 +647,7 @@ proc latencyrstat_percentiles {cmd r} {
|
||||
|
||||
proc generate_fuzzy_traffic_on_key {key duration} {
|
||||
# Commands per type, blocking commands removed
|
||||
# TODO: extract these from help.h or elsewhere, and improve to include other types
|
||||
# TODO: extract these from COMMAND DOCS, and improve to include other types
|
||||
set string_commands {APPEND BITCOUNT BITFIELD BITOP BITPOS DECR DECRBY GET GETBIT GETRANGE GETSET INCR INCRBY INCRBYFLOAT MGET MSET MSETNX PSETEX SET SETBIT SETEX SETNX SETRANGE LCS STRLEN}
|
||||
set hash_commands {HDEL HEXISTS HGET HGETALL HINCRBY HINCRBYFLOAT HKEYS HLEN HMGET HMSET HSCAN HSET HSETNX HSTRLEN HVALS HRANDFIELD}
|
||||
set zset_commands {ZADD ZCARD ZCOUNT ZINCRBY ZINTERSTORE ZLEXCOUNT ZPOPMAX ZPOPMIN ZRANGE ZRANGEBYLEX ZRANGEBYSCORE ZRANK ZREM ZREMRANGEBYLEX ZREMRANGEBYRANK ZREMRANGEBYSCORE ZREVRANGE ZREVRANGEBYLEX ZREVRANGEBYSCORE ZREVRANK ZSCAN ZSCORE ZUNIONSTORE ZRANDMEMBER}
|
||||
|
0
utils/generate-command-help.rb
Executable file → Normal file
0
utils/generate-command-help.rb
Executable file → Normal file
Loading…
Reference in New Issue
Block a user