Use linenoise completion API from redis-cli
This commit is contained in:
parent
ff4058183b
commit
41945ba6ae
159
src/redis-cli.c
159
src/redis-cli.c
@ -39,6 +39,7 @@
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
#include "hiredis.h"
|
#include "hiredis.h"
|
||||||
#include "sds.h"
|
#include "sds.h"
|
||||||
@ -89,58 +90,128 @@ static long long mstime(void) {
|
|||||||
*--------------------------------------------------------------------------- */
|
*--------------------------------------------------------------------------- */
|
||||||
|
|
||||||
/* Output command help to stdout. */
|
/* Output command help to stdout. */
|
||||||
static void outputCommandHelp(struct commandHelp *help) {
|
static void cliOutputCommandHelp(struct commandHelp *help, int group) {
|
||||||
printf("\n \x1b[1m%s\x1b[0m \x1b[90m%s\x1b[0m\n", help->name, help->params);
|
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\n", help->summary);
|
printf(" \x1b[33msummary:\x1b[0m %s\r\n", help->summary);
|
||||||
printf(" \x1b[33msince:\x1b[0m %s\n", help->since);
|
printf(" \x1b[33msince:\x1b[0m %s\r\n", help->since);
|
||||||
printf(" \x1b[33mgroup:\x1b[0m %s\n", commandGroups[help->group]);
|
if (group) {
|
||||||
|
printf(" \x1b[33mgroup:\x1b[0m %s\r\n", commandGroups[help->group]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return command group type by name string. */
|
/* Print generic help. */
|
||||||
static int commandGroupIndex(const char *name) {
|
static void cliOutputGenericHelp() {
|
||||||
int i, len = sizeof(commandGroups)/sizeof(char*);
|
printf(
|
||||||
for (i = 0; i < len; i++)
|
"redis-cli %s\r\n"
|
||||||
if (strcasecmp(name, commandGroups[i]) == 0)
|
"Type: \"help @<group>\" to get a list of commands in <group>\r\n"
|
||||||
return i;
|
" \"help <command>\" for help on <command>\r\n"
|
||||||
return -1;
|
" \"help <tab>\" to get a list of possible help topics\r\n"
|
||||||
}
|
" \"quit\" to exit\r\n",
|
||||||
|
REDIS_VERSION
|
||||||
/* Output group names. */
|
);
|
||||||
static void outputGroupHelp() {
|
|
||||||
int i, len = sizeof(commandGroups)/sizeof(char*);
|
|
||||||
for (i = 0; i < len; i++)
|
|
||||||
printf(" \x1b[90m-\x1b[0m %s\n", commandGroups[i]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Output all command help, filtering by group or command name. */
|
/* Output all command help, filtering by group or command name. */
|
||||||
static void outputHelp(int argc, char **argv) {
|
static void cliOutputHelp(int argc, char **argv) {
|
||||||
int i, len = sizeof(commandHelp) / sizeof(struct commandHelp);
|
int i, len;
|
||||||
int group;
|
|
||||||
struct commandHelp *help;
|
struct commandHelp *help;
|
||||||
|
int group = -1;
|
||||||
|
|
||||||
if (argc && strcasecmp("groups", argv[0]) == 0) {
|
if (argc == 0) {
|
||||||
outputGroupHelp();
|
cliOutputGenericHelp();
|
||||||
return;
|
return;
|
||||||
}
|
} else if (argc > 0 && argv[0][0] == '@') {
|
||||||
|
len = sizeof(commandGroups)/sizeof(char*);
|
||||||
group = argc ? commandGroupIndex(argv[0]) : -1;
|
for (i = 0; i < len; i++) {
|
||||||
for (i = 0; i < len; i++) {
|
if (strcasecmp(argv[0]+1,commandGroups[i]) == 0) {
|
||||||
help = &commandHelp[i];
|
group = i;
|
||||||
if (group == -1) {
|
break;
|
||||||
if (argc) {
|
|
||||||
if (strcasecmp(help->name, argv[0]) == 0) {
|
|
||||||
outputCommandHelp(help);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
outputCommandHelp(help);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (group == help->group) {
|
|
||||||
outputCommandHelp(help);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
puts("");
|
|
||||||
|
len = sizeof(commandHelp)/sizeof(struct commandHelp);
|
||||||
|
assert(argc > 0);
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
|
help = &commandHelp[i];
|
||||||
|
if (group == -1) {
|
||||||
|
if (strcasecmp(help->name, argv[0]) == 0) {
|
||||||
|
cliOutputCommandHelp(help,1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (group == help->group) {
|
||||||
|
cliOutputCommandHelp(help,0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf("\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CLI_COMPLETE_COMMAND 1
|
||||||
|
#define CLI_COMPLETE_GROUP 2
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char *name;
|
||||||
|
int type;
|
||||||
|
} completionEntry;
|
||||||
|
|
||||||
|
static completionEntry *completionEntries;
|
||||||
|
static int completionEntriesLen;
|
||||||
|
|
||||||
|
/* Build 2 different arrays for completion. One for raw command completion and one
|
||||||
|
* for completion using HELP (including groups). */
|
||||||
|
static void cliInitHelp() {
|
||||||
|
int commandslen = sizeof(commandHelp)/sizeof(struct commandHelp);
|
||||||
|
int groupslen = sizeof(commandGroups)/sizeof(char*);
|
||||||
|
int i, len, pos = 0;
|
||||||
|
completionEntry tmp;
|
||||||
|
|
||||||
|
completionEntriesLen = len = commandslen+groupslen;
|
||||||
|
completionEntries = malloc(sizeof(completionEntry)*len);
|
||||||
|
|
||||||
|
for (i = 0; i < groupslen; i++) {
|
||||||
|
tmp.name = malloc(strlen(commandGroups[i]+2));
|
||||||
|
sprintf(tmp.name,"@%s",commandGroups[i]);
|
||||||
|
tmp.type = CLI_COMPLETE_GROUP;
|
||||||
|
completionEntries[pos++] = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < commandslen; i++) {
|
||||||
|
tmp.name = commandHelp[i].name;
|
||||||
|
tmp.type = CLI_COMPLETE_COMMAND;
|
||||||
|
completionEntries[pos++] = tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void completionCallback(const char *buf, linenoiseCompletions *lc) {
|
||||||
|
size_t startpos = 0;
|
||||||
|
int mask;
|
||||||
|
int i;
|
||||||
|
size_t matchlen;
|
||||||
|
char *tmp;
|
||||||
|
size_t tmpsize;
|
||||||
|
|
||||||
|
if (strncasecmp(buf,"help ",5) == 0) {
|
||||||
|
startpos = 5;
|
||||||
|
while (isspace(buf[startpos])) startpos++;
|
||||||
|
mask = CLI_COMPLETE_COMMAND | CLI_COMPLETE_GROUP;
|
||||||
|
} else {
|
||||||
|
mask = CLI_COMPLETE_COMMAND;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < completionEntriesLen; i++) {
|
||||||
|
if (!(completionEntries[i].type & mask)) continue;
|
||||||
|
|
||||||
|
matchlen = strlen(buf+startpos);
|
||||||
|
if (strncasecmp(buf+startpos,completionEntries[i].name,matchlen) == 0) {
|
||||||
|
tmpsize = startpos+strlen(completionEntries[i].name)+1;
|
||||||
|
tmp = malloc(tmpsize);
|
||||||
|
memcpy(tmp,buf,startpos);
|
||||||
|
memcpy(tmp+startpos,completionEntries[i].name,tmpsize-startpos);
|
||||||
|
linenoiseAddCompletion(lc,tmp);
|
||||||
|
free(tmp);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*------------------------------------------------------------------------------
|
/*------------------------------------------------------------------------------
|
||||||
@ -318,8 +389,8 @@ static int cliSendCommand(int argc, char **argv, int repeat) {
|
|||||||
int j;
|
int j;
|
||||||
|
|
||||||
config.raw_output = !strcasecmp(command,"info");
|
config.raw_output = !strcasecmp(command,"info");
|
||||||
if (!strcasecmp(command,"help")) {
|
if (!strcasecmp(command,"help") || !strcasecmp(command,"?")) {
|
||||||
outputHelp(--argc, ++argv);
|
cliOutputHelp(--argc, ++argv);
|
||||||
return REDIS_OK;
|
return REDIS_OK;
|
||||||
}
|
}
|
||||||
if (!strcasecmp(command,"shutdown")) config.shutdown = 1;
|
if (!strcasecmp(command,"shutdown")) config.shutdown = 1;
|
||||||
@ -450,6 +521,7 @@ static void repl() {
|
|||||||
sds *argv;
|
sds *argv;
|
||||||
|
|
||||||
config.interactive = 1;
|
config.interactive = 1;
|
||||||
|
linenoiseSetCompletionCallback(completionCallback);
|
||||||
while((line = linenoise("redis> ")) != NULL) {
|
while((line = linenoise("redis> ")) != NULL) {
|
||||||
if (line[0] != '\0') {
|
if (line[0] != '\0') {
|
||||||
argv = sdssplitargs(line,&argc);
|
argv = sdssplitargs(line,&argc);
|
||||||
@ -525,6 +597,7 @@ int main(int argc, char **argv) {
|
|||||||
config.historyfile = NULL;
|
config.historyfile = NULL;
|
||||||
config.tty = isatty(fileno(stdout)) || (getenv("FAKETTY") != NULL);
|
config.tty = isatty(fileno(stdout)) || (getenv("FAKETTY") != NULL);
|
||||||
config.mb_sep = '\n';
|
config.mb_sep = '\n';
|
||||||
|
cliInitHelp();
|
||||||
|
|
||||||
if (getenv("HOME") != NULL) {
|
if (getenv("HOME") != NULL) {
|
||||||
config.historyfile = malloc(256);
|
config.historyfile = malloc(256);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user