Use linenoise completion API from redis-cli

This commit is contained in:
Pieter Noordhuis 2010-11-29 19:27:36 +01:00
parent ff4058183b
commit 41945ba6ae

View File

@ -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);