From 5397f2b596b5189edbed3e45a42d18f3c99341d6 Mon Sep 17 00:00:00 2001 From: Tj Holowaychuk Date: Tue, 16 Nov 2010 05:50:26 -0800 Subject: [PATCH 1/8] Added redis-cli interactive help support updated via commands.json in redis-doc repo. Currently use `make src/help.h` to re-generate. The following are valid from the REPL: help help [command] help [group] help groups ex: help sort help hash --- Makefile | 3 + src/help.h | 815 +++++++++++++++++++++++++++++++++ src/redis-cli.c | 19 +- utils/generate-command-help.rb | 56 +++ utils/help.h | 119 +++++ 5 files changed, 995 insertions(+), 17 deletions(-) create mode 100644 src/help.h create mode 100755 utils/generate-command-help.rb create mode 100644 utils/help.h diff --git a/Makefile b/Makefile index f67909456..d4d2c149a 100644 --- a/Makefile +++ b/Makefile @@ -11,4 +11,7 @@ install: dummy $(TARGETS) clean: cd src && $(MAKE) $@ +src/help.h: + @./utils/generate-command-help.rb > $@ + dummy: diff --git a/src/help.h b/src/help.h new file mode 100644 index 000000000..365b8b76b --- /dev/null +++ b/src/help.h @@ -0,0 +1,815 @@ + +// Auto-generated, do not edit. + +#include +#include + +/* + * List command groups. + */ + +#define GROUPS \ + G(UNKNOWN, "unknown") \ + G(SET, "set") \ + G(LIST, "list") \ + G(HASH, "hash") \ + G(GENERIC, "generic") \ + G(PUBSUB, "pubsub") \ + G(STRING, "string") \ + G(SERVER, "server") \ + G(CONNECTION, "connection") \ + G(TRANSACTIONS, "transactions") \ + G(SORTED_SET, "sorted_set") + +/* + * Command group types. + */ + +typedef enum { + #define G(GROUP, _) COMMAND_GROUP_##GROUP, + GROUPS + #undef G + COMMAND_GROUP_LENGTH +} command_group_type_t; + +/* + * Command group type names. + */ + +static char *command_group_type_names[] = { + #define G(_, STR) STR, + GROUPS + #undef G +}; + +/* + * Command help struct. + */ + +struct command_help { + char *name; + char *params; + char *summary; + command_group_type_t group; + char *since; +} command_help[] = { + { "APPEND" + , "key value" + , "Append a value to a key" + , COMMAND_GROUP_STRING + , "1.3.3" } + + , { "AUTH" + , "password" + , "Authenticate to the server" + , COMMAND_GROUP_CONNECTION + , "0.08" } + + , { "BGREWRITEAOF" + , "-" + , "Asynchronously rewrite the append-only file" + , COMMAND_GROUP_SERVER + , "1.07" } + + , { "BGSAVE" + , "-" + , "Asynchronously save the dataset to disk" + , COMMAND_GROUP_SERVER + , "0.07" } + + , { "BLPOP" + , "(key)+ timeout" + , "Remove and get the first element in a list, or block until one is available" + , COMMAND_GROUP_LIST + , "1.3.1" } + + , { "BRPOP" + , "(key)+ timeout" + , "Remove and get the last element in a list, or block until one is available" + , COMMAND_GROUP_LIST + , "1.3.1" } + + , { "CONFIG GET" + , "parameter" + , "Get the value of a configuration parameter" + , COMMAND_GROUP_SERVER + , "2.0" } + + , { "CONFIG SET" + , "parameter value" + , "Set a configuration parameter to the given value" + , COMMAND_GROUP_SERVER + , "2.0" } + + , { "DBSIZE" + , "-" + , "Return the number of keys in the selected database" + , COMMAND_GROUP_SERVER + , "0.07" } + + , { "DEBUG OBJECT" + , "key" + , "Get debugging information about a key" + , COMMAND_GROUP_SERVER + , "0.101" } + + , { "DEBUG SEGFAULT" + , "-" + , "Make the server crash" + , COMMAND_GROUP_SERVER + , "0.101" } + + , { "DECR" + , "key decrement" + , "Decrement the integer value of a key by one" + , COMMAND_GROUP_STRING + , "0.07" } + + , { "DECRBY" + , "key decrement" + , "Decrement the integer value of a key by the given number" + , COMMAND_GROUP_STRING + , "0.07" } + + , { "DEL" + , "(key)+" + , "Delete a key" + , COMMAND_GROUP_GENERIC + , "0.07" } + + , { "DISCARD" + , "-" + , "Discard all commands issued after MULTI" + , COMMAND_GROUP_TRANSACTIONS + , "1.3.3" } + + , { "ECHO" + , "message" + , "Echo the given string" + , COMMAND_GROUP_CONNECTION + , "0.07" } + + , { "EXEC" + , "-" + , "Execute all commands issued after MULTI" + , COMMAND_GROUP_TRANSACTIONS + , "1.1.95" } + + , { "EXISTS" + , "key" + , "Determine if a key exists" + , COMMAND_GROUP_SERVER + , "0.07" } + + , { "EXPIRE" + , "key seconds" + , "Set a key's time to live in seconds" + , COMMAND_GROUP_GENERIC + , "0.09" } + + , { "EXPIREAT" + , "key timestamp" + , "Set the expiration for a key as a UNIX timestamp" + , COMMAND_GROUP_GENERIC + , "1.1" } + + , { "FLUSHALL" + , "-" + , "Remove all keys from all databases" + , COMMAND_GROUP_SERVER + , "0.07" } + + , { "FLUSHDB" + , "-" + , "Remove all keys from the current database" + , COMMAND_GROUP_SERVER + , "0.07" } + + , { "GET" + , "key" + , "Get the value of a key" + , COMMAND_GROUP_STRING + , "0.07" } + + , { "GETSET" + , "key value" + , "Set the string value of a key and return its old value" + , COMMAND_GROUP_STRING + , "0.091" } + + , { "HDEL" + , "key field" + , "Delete a hash field" + , COMMAND_GROUP_HASH + , "1.3.10" } + + , { "HEXISTS" + , "key field" + , "Determine if a hash field exists" + , COMMAND_GROUP_HASH + , "1.3.10" } + + , { "HGET" + , "key field" + , "Get the value of a hash field" + , COMMAND_GROUP_HASH + , "1.3.10" } + + , { "HGETALL" + , "key" + , "Get all the fields and values in a hash" + , COMMAND_GROUP_HASH + , "1.3.10" } + + , { "HINCRBY" + , "key field increment" + , "Increment the integer value of a hash field by the given number" + , COMMAND_GROUP_HASH + , "1.3.10" } + + , { "HKEYS" + , "key" + , "Get all the fields in a hash" + , COMMAND_GROUP_HASH + , "1.3.10" } + + , { "HLEN" + , "key" + , "Get the number of fields in a hash" + , COMMAND_GROUP_HASH + , "1.3.10" } + + , { "HMGET" + , "key (field)+" + , "Get the values of all the given hash fields" + , COMMAND_GROUP_HASH + , "1.3.10" } + + , { "HMSET" + , "key (field value)+" + , "Set multiple hash fields to multiple values" + , COMMAND_GROUP_HASH + , "1.3.8" } + + , { "HSET" + , "key field value" + , "Set the string value of a hash field" + , COMMAND_GROUP_HASH + , "1.3.10" } + + , { "HSETNX" + , "key field value" + , "Set the value of a hash field, only if the field does not exist" + , COMMAND_GROUP_HASH + , "1.3.8" } + + , { "HVALS" + , "key" + , "Get all the values in a hash" + , COMMAND_GROUP_HASH + , "1.3.10" } + + , { "INCR" + , "key" + , "Increment the integer value of a key by one" + , COMMAND_GROUP_STRING + , "0.07" } + + , { "INCRBY" + , "key increment" + , "Increment the integer value of a key by the given number" + , COMMAND_GROUP_STRING + , "0.07" } + + , { "INFO" + , "-" + , "Get information and statistics about the server" + , COMMAND_GROUP_SERVER + , "0.07" } + + , { "KEYS" + , "pattern" + , "Find all keys matching the given pattern" + , COMMAND_GROUP_GENERIC + , "0.07" } + + , { "LASTSAVE" + , "-" + , "Get the UNIX time stamp of the last successful save to disk" + , COMMAND_GROUP_SERVER + , "0.07" } + + , { "LINDEX" + , "key index" + , "Get an element from a list by its index" + , COMMAND_GROUP_LIST + , "0.07" } + + , { "LINSERT" + , "key BEFORE|AFTER pivot value" + , "Insert an element before or after another element in a list" + , COMMAND_GROUP_LIST + , "2.1.1" } + + , { "LLEN" + , "key" + , "Get the length of a list" + , COMMAND_GROUP_LIST + , "0.07" } + + , { "LPOP" + , "key" + , "Remove and get the first element in a list" + , COMMAND_GROUP_LIST + , "0.07" } + + , { "LPUSH" + , "key value" + , "Prepend a value to a list" + , COMMAND_GROUP_LIST + , "0.07" } + + , { "LPUSHX" + , "key value" + , "Prepend a value to a list, only if the list exists" + , COMMAND_GROUP_LIST + , "2.1.1" } + + , { "LRANGE" + , "key start stop" + , "Get a range of elements from a list" + , COMMAND_GROUP_LIST + , "0.07" } + + , { "LREM" + , "key count value" + , "Remove elements from a list" + , COMMAND_GROUP_LIST + , "0.07" } + + , { "LSET" + , "key index value" + , "Set the value of an element in a list by its index" + , COMMAND_GROUP_LIST + , "0.07" } + + , { "LTRIM" + , "key start stop" + , "Trim a list to the specified range" + , COMMAND_GROUP_LIST + , "0.07" } + + , { "MGET" + , "(key)+" + , "Get the values of all the given keys" + , COMMAND_GROUP_STRING + , "0.07" } + + , { "MONITOR" + , "-" + , "Listen for all requests received by the server in real time" + , COMMAND_GROUP_SERVER + , "0.07" } + + , { "MOVE" + , "key db" + , "Move a key to another database" + , COMMAND_GROUP_GENERIC + , "0.07" } + + , { "MSET" + , "(key value)+" + , "Set multiple keys to multiple values" + , COMMAND_GROUP_STRING + , "1.001" } + + , { "MSETNX" + , "(key value)+" + , "Set multiple keys to multiple values, only if none of the keys exist" + , COMMAND_GROUP_STRING + , "1.001" } + + , { "MULTI" + , "-" + , "Mark the start of a transaction block" + , COMMAND_GROUP_TRANSACTIONS + , "1.1.95" } + + , { "PERSIST" + , "key" + , "Remove the expiration from a key" + , COMMAND_GROUP_GENERIC + , "2.1.2" } + + , { "PING" + , "-" + , "Ping the server" + , COMMAND_GROUP_CONNECTION + , "0.07" } + + , { "PSUBSCRIBE" + , "pattern" + , "Listen for messages published to channels matching the given patterns" + , COMMAND_GROUP_PUBSUB + , "1.3.8" } + + , { "PUBLISH" + , "channel message" + , "Post a message to a channel" + , COMMAND_GROUP_PUBSUB + , "1.3.8" } + + , { "PUNSUBSCRIBE" + , "(pattern)*" + , "Stop listening for messages posted to channels matching the given patterns" + , COMMAND_GROUP_PUBSUB + , "1.3.8" } + + , { "QUIT" + , "-" + , "Close the connection" + , COMMAND_GROUP_CONNECTION + , "0.07" } + + , { "RANDOMKEY" + , "-" + , "Return a random key from the keyspace" + , COMMAND_GROUP_GENERIC + , "0.07" } + + , { "RENAME" + , "old new" + , "Rename a key" + , COMMAND_GROUP_GENERIC + , "0.07" } + + , { "RENAMENX" + , "old new" + , "Rename a key, only if the new key does not exist" + , COMMAND_GROUP_GENERIC + , "0.07" } + + , { "RPOP" + , "key" + , "Remove and get the last element in a list" + , COMMAND_GROUP_LIST + , "0.07" } + + , { "RPOPLPUSH" + , "source destination" + , "Remove the last element in a list, append it to another list and return it" + , COMMAND_GROUP_LIST + , "1.1" } + + , { "RPUSH" + , "key value" + , "Append a value to a list" + , COMMAND_GROUP_LIST + , "0.07" } + + , { "RPUSHX" + , "key value" + , "Append a value to a list, only if the list exists" + , COMMAND_GROUP_LIST + , "2.1.1" } + + , { "SADD" + , "key member" + , "Add a member to a set" + , COMMAND_GROUP_SET + , "0.07" } + + , { "SAVE" + , "-" + , "Synchronously save the dataset to disk" + , COMMAND_GROUP_SERVER + , "0.07" } + + , { "SCARD" + , "key" + , "Get the number of members in a set" + , COMMAND_GROUP_SET + , "0.07" } + + , { "SDIFF" + , "(key)+" + , "Subtract multiple sets" + , COMMAND_GROUP_SET + , "0.100" } + + , { "SDIFFSTORE" + , "destination (key)+" + , "Subtract multiple sets and store the resulting set in a key" + , COMMAND_GROUP_SET + , "0.100" } + + , { "SELECT" + , "index" + , "Change the selected database for the current connection" + , COMMAND_GROUP_CONNECTION + , "0.07" } + + , { "SET" + , "key value" + , "Set the string value of a key" + , COMMAND_GROUP_STRING + , "0.07" } + + , { "SETEX" + , "key timestamp value" + , "Set the value and expiration of a key" + , COMMAND_GROUP_STRING + , "1.3.10" } + + , { "SETNX" + , "key value" + , "Set the value of a key, only if the key does not exist" + , COMMAND_GROUP_STRING + , "0.07" } + + , { "SHUTDOWN" + , "-" + , "Synchronously save the dataset to disk and then shut down the server" + , COMMAND_GROUP_SERVER + , "0.07" } + + , { "SINTER" + , "(key)+" + , "Intersect multiple sets" + , COMMAND_GROUP_SET + , "0.07" } + + , { "SINTERSTORE" + , "destination (key)+" + , "Intersect multiple sets and store the resulting set in a key" + , COMMAND_GROUP_SET + , "0.07" } + + , { "SISMEMBER" + , "key member" + , "Determine if a given value is a member of a set" + , COMMAND_GROUP_SET + , "0.07" } + + , { "SLAVEOF" + , "host port" + , "Make the server a slave of another instance, or promote it as master" + , COMMAND_GROUP_SERVER + , "0.100" } + + , { "SMEMBERS" + , "key" + , "Get all the members in a set" + , COMMAND_GROUP_SET + , "0.07" } + + , { "SMOVE" + , "source destination member" + , "Move a member from one set to another" + , COMMAND_GROUP_SET + , "0.091" } + + , { "SORT" + , "key (BY pattern)? (LIMIT start count)? (GET pattern)* (ASC|DESC)? (ALPHA)? (STORE destination)?" + , "Sort the elements in a list, set or sorted set" + , COMMAND_GROUP_GENERIC + , "0.07" } + + , { "SPOP" + , "key" + , "Remove and return a random member from a set" + , COMMAND_GROUP_SET + , "0.101" } + + , { "SRANDMEMBER" + , "key" + , "Get a random member from a set" + , COMMAND_GROUP_SET + , "1.001" } + + , { "SREM" + , "key member" + , "Remove a member from a set" + , COMMAND_GROUP_SET + , "0.07" } + + , { "STRLEN" + , "key" + , "Get the length of the value stored in a key" + , COMMAND_GROUP_STRING + , "2.1.2" } + + , { "SUBSCRIBE" + , "channel" + , "Listen for messages published to the given channels" + , COMMAND_GROUP_PUBSUB + , "1.3.8" } + + , { "SUBSTR" + , "key start stop" + , "Get a substring of the string stored at a key" + , COMMAND_GROUP_STRING + , "1.3.4" } + + , { "SUNION" + , "(key)+" + , "Add multiple sets" + , COMMAND_GROUP_SET + , "0.091" } + + , { "SUNIONSTORE" + , "destination (key)+" + , "Add multiple sets and store the resulting set in a key" + , COMMAND_GROUP_SET + , "0.091" } + + , { "SYNC" + , "-" + , "Internal command used for replication" + , COMMAND_GROUP_SERVER + , "0.07" } + + , { "TTL" + , "key" + , "Get the time to live for a key" + , COMMAND_GROUP_GENERIC + , "0.100" } + + , { "TYPE" + , "key" + , "Determine the type stored at key" + , COMMAND_GROUP_GENERIC + , "0.07" } + + , { "UNSUBSCRIBE" + , "(channel)*" + , "Stop listening for messages posted to the given channels" + , COMMAND_GROUP_PUBSUB + , "1.3.8" } + + , { "UNWATCH" + , "-" + , "Forget about all watched keys" + , COMMAND_GROUP_TRANSACTIONS + , "2.1.0" } + + , { "WATCH" + , "(key)+" + , "Watch the given keys to determine execution of the MULTI/EXEC block" + , COMMAND_GROUP_TRANSACTIONS + , "2.1.0" } + + , { "ZADD" + , "key score member" + , "Add a member to a sorted set, or update its score if it already exists" + , COMMAND_GROUP_SORTED_SET + , "1.1" } + + , { "ZCARD" + , "key" + , "Get the number of members in a sorted set" + , COMMAND_GROUP_SORTED_SET + , "1.1" } + + , { "ZCOUNT" + , "key min max" + , "Count the members in a sorted set with scores within the given values" + , COMMAND_GROUP_SORTED_SET + , "1.3.3" } + + , { "ZINCRBY" + , "key increment member" + , "Increment the score of a member in a sorted set" + , COMMAND_GROUP_SORTED_SET + , "1.1" } + + , { "ZINTERSTORE" + , "destination (key)+ (WEIGHTS weight)? (AGGREGATE SUM|MIN|MAX)?" + , "Intersect multiple sorted sets and store the resulting sorted set in a new key" + , COMMAND_GROUP_SORTED_SET + , "1.3.10" } + + , { "ZRANGE" + , "key start stop" + , "Return a range of members in a sorted set, by index" + , COMMAND_GROUP_SORTED_SET + , "1.1" } + + , { "ZRANGEBYSCORE" + , "key min max" + , "Return a range of members in a sorted set, by score" + , COMMAND_GROUP_SORTED_SET + , "1.050" } + + , { "ZRANK" + , "key member" + , "Determine the index of a member in a sorted set" + , COMMAND_GROUP_SORTED_SET + , "1.3.4" } + + , { "ZREM" + , "key member" + , "Remove a member from a sorted set" + , COMMAND_GROUP_SORTED_SET + , "1.1" } + + , { "ZREMRANGEBYRANK" + , "key start stop" + , "Remove all members in a sorted set within the given indexes" + , COMMAND_GROUP_SORTED_SET + , "1.3.4" } + + , { "ZREMRANGEBYSCORE" + , "key min max" + , "Remove all members in a sorted set within the given scores" + , COMMAND_GROUP_SORTED_SET + , "1.1" } + + , { "ZREVRANGE" + , "key start stop" + , "Return a range of members in a sorted set, by index, with scores ordered from high to low" + , COMMAND_GROUP_SORTED_SET + , "1.1" } + + , { "ZREVRANK" + , "key member" + , "Determine the index of a member in a sorted set, with scores ordered from high to low" + , COMMAND_GROUP_SORTED_SET + , "1.3.4" } + + , { "ZSCORE" + , "key member" + , "Get the score associated with the given member in a sorted set" + , COMMAND_GROUP_SORTED_SET + , "1.1" } + + , { "ZUNIONSTORE" + , "destination (key)+ (WEIGHTS weight)? (AGGREGATE SUM|MIN|MAX)?" + , "Add multiple sorted sets and store the resulting sorted set in a new key" + , COMMAND_GROUP_SORTED_SET + , "1.3.10" } +}; + +/* + * Output command help to stdout. + */ + +static void +output_command_help(struct command_help *help) { + printf("\n \x1b[1m%s\x1b[0m \x1b[90m%s\x1b[0m\n", help->name, help->params); + printf(" \x1b[33msummary:\x1b[0m %s\n", help->summary); + printf(" \x1b[33msince:\x1b[0m %s\n", help->since); + printf(" \x1b[33mgroup:\x1b[0m %s\n", command_group_type_names[help->group]); +} + +/* + * Return command group type by name string. + */ + +static command_group_type_t +command_group_type_by_name(const char *name) { + for (int i = 0; i < COMMAND_GROUP_LENGTH; ++i) { + const char *group = command_group_type_names[i]; + if (0 == strcasecmp(name, group)) return i; + } + return 0; +} + +/* + * Output group names. + */ + +static void +output_group_help() { + for (int i = 0; i < COMMAND_GROUP_LENGTH; ++i) { + if (COMMAND_GROUP_UNKNOWN == i) continue; + const char *group = command_group_type_names[i]; + printf(" \x1b[90m-\x1b[0m %s\n", group); + } +} + +/* + * Output all command help, filtering by group or command name. + */ + +static void +output_help(int argc, const char **argv) { + int len = sizeof(command_help) / sizeof(struct command_help); + + if (argc && 0 == strcasecmp("groups", argv[0])) { + output_group_help(); + return; + } + + command_group_type_t group = argc + ? command_group_type_by_name(argv[0]) + : COMMAND_GROUP_UNKNOWN; + + for (int i = 0; i < len; ++i) { + struct command_help help = command_help[i]; + if (argc && !group && 0 != strcasecmp(help.name, argv[0])) continue; + if (group && group != help.group) continue; + output_command_help(&help); + } + puts(""); +} diff --git a/src/redis-cli.c b/src/redis-cli.c index aa7306b44..6ae77545e 100644 --- a/src/redis-cli.c +++ b/src/redis-cli.c @@ -44,6 +44,7 @@ #include "adlist.h" #include "zmalloc.h" #include "linenoise.h" +#include "help.h" #define REDIS_NOTUSED(V) ((void) V) @@ -248,22 +249,6 @@ static int selectDb(int fd) { return 0; } -static void showInteractiveHelp(void) { - printf( - "\n" - "Welcome to redis-cli " REDIS_VERSION "!\n" - "Just type any valid Redis command to see a pretty printed output.\n" - "\n" - "It is possible to quote strings, like in:\n" - " set \"my key\" \"some string \\xff\\n\"\n" - "\n" - "You can find a list of valid Redis commands at\n" - " http://code.google.com/p/redis/wiki/CommandReference\n" - "\n" - "Note: redis-cli supports line editing, use up/down arrows for history." - "\n\n"); -} - static int cliSendCommand(int argc, char **argv, int repeat) { char *command = argv[0]; int fd, j, retval = 0; @@ -271,7 +256,7 @@ static int cliSendCommand(int argc, char **argv, int repeat) { config.raw_output = !strcasecmp(command,"info"); if (!strcasecmp(command,"help")) { - showInteractiveHelp(); + output_help(--argc, ++argv); return 0; } if (!strcasecmp(command,"shutdown")) config.shutdown = 1; diff --git a/utils/generate-command-help.rb b/utils/generate-command-help.rb new file mode 100755 index 000000000..250a2159e --- /dev/null +++ b/utils/generate-command-help.rb @@ -0,0 +1,56 @@ +#!/usr/bin/env ruby + +require 'net/http' +require 'net/https' +require 'json' +require 'uri' + +dest = ARGV[0] +tmpl = File.read './utils/help.h' + +url = URI.parse 'https://github.com/antirez/redis-doc/raw/master/commands.json' +client = Net::HTTP.new url.host, url.port +client.use_ssl = true +res = client.get url.path + +def argument arg + name = arg['name'].is_a?(Array) ? arg['name'].join(' ') : arg['name'] + name = arg['enum'].join '|' if 'enum' == arg['type'] + name = arg['command'] + ' ' + name if arg['command'] + if arg['multiple'] + name = "(#{name})" + name += arg['optional'] ? '*' : '+' + elsif arg['optional'] + name = "(#{name})?" + end + name +end + +def arguments command + return '-' unless command['arguments'] + command['arguments'].map do |arg| + argument arg + end.join ' ' +end + +case res +when Net::HTTPSuccess + first = true + commands = JSON.parse(res.body) + c = commands.map do |key, command| + buf = if first + first = false + ' ' + else + "\n ," + end + buf += " { \"#{key}\"\n" + + " , \"#{arguments(command)}\"\n" + + " , \"#{command['summary']}\"\n" + + " , COMMAND_GROUP_#{command['group'].upcase}\n" + + " , \"#{command['since']}\" }" + end.join("\n") + puts "\n// Auto-generated, do not edit.\n" + tmpl.sub('__COMMANDS__', c) +else + res.error! +end \ No newline at end of file diff --git a/utils/help.h b/utils/help.h new file mode 100644 index 000000000..dc7f270d9 --- /dev/null +++ b/utils/help.h @@ -0,0 +1,119 @@ + +#include +#include + +/* + * List command groups. + */ + +#define GROUPS \ + G(UNKNOWN, "unknown") \ + G(SET, "set") \ + G(LIST, "list") \ + G(HASH, "hash") \ + G(GENERIC, "generic") \ + G(PUBSUB, "pubsub") \ + G(STRING, "string") \ + G(SERVER, "server") \ + G(CONNECTION, "connection") \ + G(TRANSACTIONS, "transactions") \ + G(SORTED_SET, "sorted_set") + +/* + * Command group types. + */ + +typedef enum { + #define G(GROUP, _) COMMAND_GROUP_##GROUP, + GROUPS + #undef G + COMMAND_GROUP_LENGTH +} command_group_type_t; + +/* + * Command group type names. + */ + +static char *command_group_type_names[] = { + #define G(_, STR) STR, + GROUPS + #undef G +}; + +/* + * Command help struct. + */ + +struct command_help { + char *name; + char *params; + char *summary; + command_group_type_t group; + char *since; +} command_help[] = { + __COMMANDS__ +}; + +/* + * Output command help to stdout. + */ + +static void +output_command_help(struct command_help *help) { + printf("\n \x1b[1m%s\x1b[0m \x1b[90m%s\x1b[0m\n", help->name, help->params); + printf(" \x1b[33msummary:\x1b[0m %s\n", help->summary); + printf(" \x1b[33msince:\x1b[0m %s\n", help->since); + printf(" \x1b[33mgroup:\x1b[0m %s\n", command_group_type_names[help->group]); +} + +/* + * Return command group type by name string. + */ + +static command_group_type_t +command_group_type_by_name(const char *name) { + for (int i = 0; i < COMMAND_GROUP_LENGTH; ++i) { + const char *group = command_group_type_names[i]; + if (0 == strcasecmp(name, group)) return i; + } + return 0; +} + +/* + * Output group names. + */ + +static void +output_group_help() { + for (int i = 0; i < COMMAND_GROUP_LENGTH; ++i) { + if (COMMAND_GROUP_UNKNOWN == i) continue; + const char *group = command_group_type_names[i]; + printf(" \x1b[90m-\x1b[0m %s\n", group); + } +} + +/* + * Output all command help, filtering by group or command name. + */ + +static void +output_help(int argc, const char **argv) { + int len = sizeof(command_help) / sizeof(struct command_help); + + if (argc && 0 == strcasecmp("groups", argv[0])) { + output_group_help(); + return; + } + + command_group_type_t group = argc + ? command_group_type_by_name(argv[0]) + : COMMAND_GROUP_UNKNOWN; + + for (int i = 0; i < len; ++i) { + struct command_help help = command_help[i]; + if (argc && !group && 0 != strcasecmp(help.name, argv[0])) continue; + if (group && group != help.group) continue; + output_command_help(&help); + } + puts(""); +} \ No newline at end of file From 50d0e82d54d9fcc7f42443a9cde51d812934b3c1 Mon Sep 17 00:00:00 2001 From: Pieter Noordhuis Date: Sun, 28 Nov 2010 17:45:58 +0100 Subject: [PATCH 2/8] Update help.h generator script to output man-style argument list --- src/help.h | 1274 +++++++++++++++----------------- utils/generate-command-help.rb | 93 +-- 2 files changed, 628 insertions(+), 739 deletions(-) diff --git a/src/help.h b/src/help.h index 365b8b76b..ba9b299a9 100644 --- a/src/help.h +++ b/src/help.h @@ -53,701 +53,587 @@ struct command_help { command_group_type_t group; char *since; } command_help[] = { - { "APPEND" - , "key value" - , "Append a value to a key" - , COMMAND_GROUP_STRING - , "1.3.3" } + { "APPEND", + "key value", + "Append a value to a key", + COMMAND_GROUP_STRING, + "1.3.3" } +, { "AUTH", + "password", + "Authenticate to the server", + COMMAND_GROUP_CONNECTION, + "0.08" } +, { "BGREWRITEAOF", + "-", + "Asynchronously rewrite the append-only file", + COMMAND_GROUP_SERVER, + "1.07" } +, { "BGSAVE", + "-", + "Asynchronously save the dataset to disk", + COMMAND_GROUP_SERVER, + "0.07" } +, { "BLPOP", + "key [key ...] timeout", + "Remove and get the first element in a list, or block until one is available", + COMMAND_GROUP_LIST, + "1.3.1" } +, { "BRPOP", + "key [key ...] timeout", + "Remove and get the last element in a list, or block until one is available", + COMMAND_GROUP_LIST, + "1.3.1" } +, { "CONFIG GET", + "parameter", + "Get the value of a configuration parameter", + COMMAND_GROUP_SERVER, + "2.0" } +, { "CONFIG SET", + "parameter value", + "Set a configuration parameter to the given value", + COMMAND_GROUP_SERVER, + "2.0" } +, { "DBSIZE", + "-", + "Return the number of keys in the selected database", + COMMAND_GROUP_SERVER, + "0.07" } +, { "DEBUG OBJECT", + "key", + "Get debugging information about a key", + COMMAND_GROUP_SERVER, + "0.101" } +, { "DEBUG SEGFAULT", + "-", + "Make the server crash", + COMMAND_GROUP_SERVER, + "0.101" } +, { "DECR", + "key decrement", + "Decrement the integer value of a key by one", + COMMAND_GROUP_STRING, + "0.07" } +, { "DECRBY", + "key decrement", + "Decrement the integer value of a key by the given number", + COMMAND_GROUP_STRING, + "0.07" } +, { "DEL", + "key [key ...]", + "Delete a key", + COMMAND_GROUP_GENERIC, + "0.07" } +, { "DISCARD", + "-", + "Discard all commands issued after MULTI", + COMMAND_GROUP_TRANSACTIONS, + "1.3.3" } +, { "ECHO", + "message", + "Echo the given string", + COMMAND_GROUP_CONNECTION, + "0.07" } +, { "EXEC", + "-", + "Execute all commands issued after MULTI", + COMMAND_GROUP_TRANSACTIONS, + "1.1.95" } +, { "EXISTS", + "key", + "Determine if a key exists", + COMMAND_GROUP_SERVER, + "0.07" } +, { "EXPIRE", + "key seconds", + "Set a key's time to live in seconds", + COMMAND_GROUP_GENERIC, + "0.09" } +, { "EXPIREAT", + "key timestamp", + "Set the expiration for a key as a UNIX timestamp", + COMMAND_GROUP_GENERIC, + "1.1" } +, { "FLUSHALL", + "-", + "Remove all keys from all databases", + COMMAND_GROUP_SERVER, + "0.07" } +, { "FLUSHDB", + "-", + "Remove all keys from the current database", + COMMAND_GROUP_SERVER, + "0.07" } +, { "GET", + "key", + "Get the value of a key", + COMMAND_GROUP_STRING, + "0.07" } +, { "GETSET", + "key value", + "Set the string value of a key and return its old value", + COMMAND_GROUP_STRING, + "0.091" } +, { "HDEL", + "key field", + "Delete a hash field", + COMMAND_GROUP_HASH, + "1.3.10" } +, { "HEXISTS", + "key field", + "Determine if a hash field exists", + COMMAND_GROUP_HASH, + "1.3.10" } +, { "HGET", + "key field", + "Get the value of a hash field", + COMMAND_GROUP_HASH, + "1.3.10" } +, { "HGETALL", + "key", + "Get all the fields and values in a hash", + COMMAND_GROUP_HASH, + "1.3.10" } +, { "HINCRBY", + "key field increment", + "Increment the integer value of a hash field by the given number", + COMMAND_GROUP_HASH, + "1.3.10" } +, { "HKEYS", + "key", + "Get all the fields in a hash", + COMMAND_GROUP_HASH, + "1.3.10" } +, { "HLEN", + "key", + "Get the number of fields in a hash", + COMMAND_GROUP_HASH, + "1.3.10" } +, { "HMGET", + "key field [field ...]", + "Get the values of all the given hash fields", + COMMAND_GROUP_HASH, + "1.3.10" } +, { "HMSET", + "key field value [field value ...]", + "Set multiple hash fields to multiple values", + COMMAND_GROUP_HASH, + "1.3.8" } +, { "HSET", + "key field value", + "Set the string value of a hash field", + COMMAND_GROUP_HASH, + "1.3.10" } +, { "HSETNX", + "key field value", + "Set the value of a hash field, only if the field does not exist", + COMMAND_GROUP_HASH, + "1.3.8" } +, { "HVALS", + "key", + "Get all the values in a hash", + COMMAND_GROUP_HASH, + "1.3.10" } +, { "INCR", + "key", + "Increment the integer value of a key by one", + COMMAND_GROUP_STRING, + "0.07" } +, { "INCRBY", + "key increment", + "Increment the integer value of a key by the given number", + COMMAND_GROUP_STRING, + "0.07" } +, { "INFO", + "-", + "Get information and statistics about the server", + COMMAND_GROUP_SERVER, + "0.07" } +, { "KEYS", + "pattern", + "Find all keys matching the given pattern", + COMMAND_GROUP_GENERIC, + "0.07" } +, { "LASTSAVE", + "-", + "Get the UNIX time stamp of the last successful save to disk", + COMMAND_GROUP_SERVER, + "0.07" } +, { "LINDEX", + "key index", + "Get an element from a list by its index", + COMMAND_GROUP_LIST, + "0.07" } +, { "LINSERT", + "key BEFORE|AFTER pivot value", + "Insert an element before or after another element in a list", + COMMAND_GROUP_LIST, + "2.1.1" } +, { "LLEN", + "key", + "Get the length of a list", + COMMAND_GROUP_LIST, + "0.07" } +, { "LPOP", + "key", + "Remove and get the first element in a list", + COMMAND_GROUP_LIST, + "0.07" } +, { "LPUSH", + "key value", + "Prepend a value to a list", + COMMAND_GROUP_LIST, + "0.07" } +, { "LPUSHX", + "key value", + "Prepend a value to a list, only if the list exists", + COMMAND_GROUP_LIST, + "2.1.1" } +, { "LRANGE", + "key start stop", + "Get a range of elements from a list", + COMMAND_GROUP_LIST, + "0.07" } +, { "LREM", + "key count value", + "Remove elements from a list", + COMMAND_GROUP_LIST, + "0.07" } +, { "LSET", + "key index value", + "Set the value of an element in a list by its index", + COMMAND_GROUP_LIST, + "0.07" } +, { "LTRIM", + "key start stop", + "Trim a list to the specified range", + COMMAND_GROUP_LIST, + "0.07" } +, { "MGET", + "key [key ...]", + "Get the values of all the given keys", + COMMAND_GROUP_STRING, + "0.07" } +, { "MONITOR", + "-", + "Listen for all requests received by the server in real time", + COMMAND_GROUP_SERVER, + "0.07" } +, { "MOVE", + "key db", + "Move a key to another database", + COMMAND_GROUP_GENERIC, + "0.07" } +, { "MSET", + "key value [key value ...]", + "Set multiple keys to multiple values", + COMMAND_GROUP_STRING, + "1.001" } +, { "MSETNX", + "key value [key value ...]", + "Set multiple keys to multiple values, only if none of the keys exist", + COMMAND_GROUP_STRING, + "1.001" } +, { "MULTI", + "-", + "Mark the start of a transaction block", + COMMAND_GROUP_TRANSACTIONS, + "1.1.95" } +, { "PERSIST", + "key", + "Remove the expiration from a key", + COMMAND_GROUP_GENERIC, + "2.1.2" } +, { "PING", + "-", + "Ping the server", + COMMAND_GROUP_CONNECTION, + "0.07" } +, { "PSUBSCRIBE", + "pattern", + "Listen for messages published to channels matching the given patterns", + COMMAND_GROUP_PUBSUB, + "1.3.8" } +, { "PUBLISH", + "channel message", + "Post a message to a channel", + COMMAND_GROUP_PUBSUB, + "1.3.8" } +, { "PUNSUBSCRIBE", + "[pattern [pattern ...]]", + "Stop listening for messages posted to channels matching the given patterns", + COMMAND_GROUP_PUBSUB, + "1.3.8" } +, { "QUIT", + "-", + "Close the connection", + COMMAND_GROUP_CONNECTION, + "0.07" } +, { "RANDOMKEY", + "-", + "Return a random key from the keyspace", + COMMAND_GROUP_GENERIC, + "0.07" } +, { "RENAME", + "old new", + "Rename a key", + COMMAND_GROUP_GENERIC, + "0.07" } +, { "RENAMENX", + "old new", + "Rename a key, only if the new key does not exist", + COMMAND_GROUP_GENERIC, + "0.07" } +, { "RPOP", + "key", + "Remove and get the last element in a list", + COMMAND_GROUP_LIST, + "0.07" } +, { "RPOPLPUSH", + "source destination", + "Remove the last element in a list, append it to another list and return it", + COMMAND_GROUP_LIST, + "1.1" } +, { "RPUSH", + "key value", + "Append a value to a list", + COMMAND_GROUP_LIST, + "0.07" } +, { "RPUSHX", + "key value", + "Append a value to a list, only if the list exists", + COMMAND_GROUP_LIST, + "2.1.1" } +, { "SADD", + "key member", + "Add a member to a set", + COMMAND_GROUP_SET, + "0.07" } +, { "SAVE", + "-", + "Synchronously save the dataset to disk", + COMMAND_GROUP_SERVER, + "0.07" } +, { "SCARD", + "key", + "Get the number of members in a set", + COMMAND_GROUP_SET, + "0.07" } +, { "SDIFF", + "key [key ...]", + "Subtract multiple sets", + COMMAND_GROUP_SET, + "0.100" } +, { "SDIFFSTORE", + "destination key [key ...]", + "Subtract multiple sets and store the resulting set in a key", + COMMAND_GROUP_SET, + "0.100" } +, { "SELECT", + "index", + "Change the selected database for the current connection", + COMMAND_GROUP_CONNECTION, + "0.07" } +, { "SET", + "key value", + "Set the string value of a key", + COMMAND_GROUP_STRING, + "0.07" } +, { "SETEX", + "key timestamp value", + "Set the value and expiration of a key", + COMMAND_GROUP_STRING, + "1.3.10" } +, { "SETNX", + "key value", + "Set the value of a key, only if the key does not exist", + COMMAND_GROUP_STRING, + "0.07" } +, { "SHUTDOWN", + "-", + "Synchronously save the dataset to disk and then shut down the server", + COMMAND_GROUP_SERVER, + "0.07" } +, { "SINTER", + "key [key ...]", + "Intersect multiple sets", + COMMAND_GROUP_SET, + "0.07" } +, { "SINTERSTORE", + "destination key [key ...]", + "Intersect multiple sets and store the resulting set in a key", + COMMAND_GROUP_SET, + "0.07" } +, { "SISMEMBER", + "key member", + "Determine if a given value is a member of a set", + COMMAND_GROUP_SET, + "0.07" } +, { "SLAVEOF", + "host port", + "Make the server a slave of another instance, or promote it as master", + COMMAND_GROUP_SERVER, + "0.100" } +, { "SMEMBERS", + "key", + "Get all the members in a set", + COMMAND_GROUP_SET, + "0.07" } +, { "SMOVE", + "source destination member", + "Move a member from one set to another", + COMMAND_GROUP_SET, + "0.091" } +, { "SORT", + "key [BY pattern] [LIMIT start count] [GET pattern [GET pattern ...]] [ASC|DESC] [ALPHA] [STORE destination]", + "Sort the elements in a list, set or sorted set", + COMMAND_GROUP_GENERIC, + "0.07" } +, { "SPOP", + "key", + "Remove and return a random member from a set", + COMMAND_GROUP_SET, + "0.101" } +, { "SRANDMEMBER", + "key", + "Get a random member from a set", + COMMAND_GROUP_SET, + "1.001" } +, { "SREM", + "key member", + "Remove a member from a set", + COMMAND_GROUP_SET, + "0.07" } +, { "STRLEN", + "key", + "Get the length of the value stored in a key", + COMMAND_GROUP_STRING, + "2.1.2" } +, { "SUBSCRIBE", + "channel", + "Listen for messages published to the given channels", + COMMAND_GROUP_PUBSUB, + "1.3.8" } +, { "SUBSTR", + "key start stop", + "Get a substring of the string stored at a key", + COMMAND_GROUP_STRING, + "1.3.4" } +, { "SUNION", + "key [key ...]", + "Add multiple sets", + COMMAND_GROUP_SET, + "0.091" } +, { "SUNIONSTORE", + "destination key [key ...]", + "Add multiple sets and store the resulting set in a key", + COMMAND_GROUP_SET, + "0.091" } +, { "SYNC", + "-", + "Internal command used for replication", + COMMAND_GROUP_SERVER, + "0.07" } +, { "TTL", + "key", + "Get the time to live for a key", + COMMAND_GROUP_GENERIC, + "0.100" } +, { "TYPE", + "key", + "Determine the type stored at key", + COMMAND_GROUP_GENERIC, + "0.07" } +, { "UNSUBSCRIBE", + "[channel [channel ...]]", + "Stop listening for messages posted to the given channels", + COMMAND_GROUP_PUBSUB, + "1.3.8" } +, { "UNWATCH", + "-", + "Forget about all watched keys", + COMMAND_GROUP_TRANSACTIONS, + "2.1.0" } +, { "WATCH", + "key [key ...]", + "Watch the given keys to determine execution of the MULTI/EXEC block", + COMMAND_GROUP_TRANSACTIONS, + "2.1.0" } +, { "ZADD", + "key score member", + "Add a member to a sorted set, or update its score if it already exists", + COMMAND_GROUP_SORTED_SET, + "1.1" } +, { "ZCARD", + "key", + "Get the number of members in a sorted set", + COMMAND_GROUP_SORTED_SET, + "1.1" } +, { "ZCOUNT", + "key min max", + "Count the members in a sorted set with scores within the given values", + COMMAND_GROUP_SORTED_SET, + "1.3.3" } +, { "ZINCRBY", + "key increment member", + "Increment the score of a member in a sorted set", + COMMAND_GROUP_SORTED_SET, + "1.1" } +, { "ZINTERSTORE", + "destination key [key ...] [WEIGHTS weight] [AGGREGATE SUM|MIN|MAX]", + "Intersect multiple sorted sets and store the resulting sorted set in a new key", + COMMAND_GROUP_SORTED_SET, + "1.3.10" } +, { "ZRANGE", + "key start stop", + "Return a range of members in a sorted set, by index", + COMMAND_GROUP_SORTED_SET, + "1.1" } +, { "ZRANGEBYSCORE", + "key min max", + "Return a range of members in a sorted set, by score", + COMMAND_GROUP_SORTED_SET, + "1.050" } +, { "ZRANK", + "key member", + "Determine the index of a member in a sorted set", + COMMAND_GROUP_SORTED_SET, + "1.3.4" } +, { "ZREM", + "key member", + "Remove a member from a sorted set", + COMMAND_GROUP_SORTED_SET, + "1.1" } +, { "ZREMRANGEBYRANK", + "key start stop", + "Remove all members in a sorted set within the given indexes", + COMMAND_GROUP_SORTED_SET, + "1.3.4" } +, { "ZREMRANGEBYSCORE", + "key min max", + "Remove all members in a sorted set within the given scores", + COMMAND_GROUP_SORTED_SET, + "1.1" } +, { "ZREVRANGE", + "key start stop", + "Return a range of members in a sorted set, by index, with scores ordered from high to low", + COMMAND_GROUP_SORTED_SET, + "1.1" } +, { "ZREVRANK", + "key member", + "Determine the index of a member in a sorted set, with scores ordered from high to low", + COMMAND_GROUP_SORTED_SET, + "1.3.4" } +, { "ZSCORE", + "key member", + "Get the score associated with the given member in a sorted set", + COMMAND_GROUP_SORTED_SET, + "1.1" } +, { "ZUNIONSTORE", + "destination key [key ...] [WEIGHTS weight] [AGGREGATE SUM|MIN|MAX]", + "Add multiple sorted sets and store the resulting sorted set in a new key", + COMMAND_GROUP_SORTED_SET, + "1.3.10" } - , { "AUTH" - , "password" - , "Authenticate to the server" - , COMMAND_GROUP_CONNECTION - , "0.08" } - - , { "BGREWRITEAOF" - , "-" - , "Asynchronously rewrite the append-only file" - , COMMAND_GROUP_SERVER - , "1.07" } - - , { "BGSAVE" - , "-" - , "Asynchronously save the dataset to disk" - , COMMAND_GROUP_SERVER - , "0.07" } - - , { "BLPOP" - , "(key)+ timeout" - , "Remove and get the first element in a list, or block until one is available" - , COMMAND_GROUP_LIST - , "1.3.1" } - - , { "BRPOP" - , "(key)+ timeout" - , "Remove and get the last element in a list, or block until one is available" - , COMMAND_GROUP_LIST - , "1.3.1" } - - , { "CONFIG GET" - , "parameter" - , "Get the value of a configuration parameter" - , COMMAND_GROUP_SERVER - , "2.0" } - - , { "CONFIG SET" - , "parameter value" - , "Set a configuration parameter to the given value" - , COMMAND_GROUP_SERVER - , "2.0" } - - , { "DBSIZE" - , "-" - , "Return the number of keys in the selected database" - , COMMAND_GROUP_SERVER - , "0.07" } - - , { "DEBUG OBJECT" - , "key" - , "Get debugging information about a key" - , COMMAND_GROUP_SERVER - , "0.101" } - - , { "DEBUG SEGFAULT" - , "-" - , "Make the server crash" - , COMMAND_GROUP_SERVER - , "0.101" } - - , { "DECR" - , "key decrement" - , "Decrement the integer value of a key by one" - , COMMAND_GROUP_STRING - , "0.07" } - - , { "DECRBY" - , "key decrement" - , "Decrement the integer value of a key by the given number" - , COMMAND_GROUP_STRING - , "0.07" } - - , { "DEL" - , "(key)+" - , "Delete a key" - , COMMAND_GROUP_GENERIC - , "0.07" } - - , { "DISCARD" - , "-" - , "Discard all commands issued after MULTI" - , COMMAND_GROUP_TRANSACTIONS - , "1.3.3" } - - , { "ECHO" - , "message" - , "Echo the given string" - , COMMAND_GROUP_CONNECTION - , "0.07" } - - , { "EXEC" - , "-" - , "Execute all commands issued after MULTI" - , COMMAND_GROUP_TRANSACTIONS - , "1.1.95" } - - , { "EXISTS" - , "key" - , "Determine if a key exists" - , COMMAND_GROUP_SERVER - , "0.07" } - - , { "EXPIRE" - , "key seconds" - , "Set a key's time to live in seconds" - , COMMAND_GROUP_GENERIC - , "0.09" } - - , { "EXPIREAT" - , "key timestamp" - , "Set the expiration for a key as a UNIX timestamp" - , COMMAND_GROUP_GENERIC - , "1.1" } - - , { "FLUSHALL" - , "-" - , "Remove all keys from all databases" - , COMMAND_GROUP_SERVER - , "0.07" } - - , { "FLUSHDB" - , "-" - , "Remove all keys from the current database" - , COMMAND_GROUP_SERVER - , "0.07" } - - , { "GET" - , "key" - , "Get the value of a key" - , COMMAND_GROUP_STRING - , "0.07" } - - , { "GETSET" - , "key value" - , "Set the string value of a key and return its old value" - , COMMAND_GROUP_STRING - , "0.091" } - - , { "HDEL" - , "key field" - , "Delete a hash field" - , COMMAND_GROUP_HASH - , "1.3.10" } - - , { "HEXISTS" - , "key field" - , "Determine if a hash field exists" - , COMMAND_GROUP_HASH - , "1.3.10" } - - , { "HGET" - , "key field" - , "Get the value of a hash field" - , COMMAND_GROUP_HASH - , "1.3.10" } - - , { "HGETALL" - , "key" - , "Get all the fields and values in a hash" - , COMMAND_GROUP_HASH - , "1.3.10" } - - , { "HINCRBY" - , "key field increment" - , "Increment the integer value of a hash field by the given number" - , COMMAND_GROUP_HASH - , "1.3.10" } - - , { "HKEYS" - , "key" - , "Get all the fields in a hash" - , COMMAND_GROUP_HASH - , "1.3.10" } - - , { "HLEN" - , "key" - , "Get the number of fields in a hash" - , COMMAND_GROUP_HASH - , "1.3.10" } - - , { "HMGET" - , "key (field)+" - , "Get the values of all the given hash fields" - , COMMAND_GROUP_HASH - , "1.3.10" } - - , { "HMSET" - , "key (field value)+" - , "Set multiple hash fields to multiple values" - , COMMAND_GROUP_HASH - , "1.3.8" } - - , { "HSET" - , "key field value" - , "Set the string value of a hash field" - , COMMAND_GROUP_HASH - , "1.3.10" } - - , { "HSETNX" - , "key field value" - , "Set the value of a hash field, only if the field does not exist" - , COMMAND_GROUP_HASH - , "1.3.8" } - - , { "HVALS" - , "key" - , "Get all the values in a hash" - , COMMAND_GROUP_HASH - , "1.3.10" } - - , { "INCR" - , "key" - , "Increment the integer value of a key by one" - , COMMAND_GROUP_STRING - , "0.07" } - - , { "INCRBY" - , "key increment" - , "Increment the integer value of a key by the given number" - , COMMAND_GROUP_STRING - , "0.07" } - - , { "INFO" - , "-" - , "Get information and statistics about the server" - , COMMAND_GROUP_SERVER - , "0.07" } - - , { "KEYS" - , "pattern" - , "Find all keys matching the given pattern" - , COMMAND_GROUP_GENERIC - , "0.07" } - - , { "LASTSAVE" - , "-" - , "Get the UNIX time stamp of the last successful save to disk" - , COMMAND_GROUP_SERVER - , "0.07" } - - , { "LINDEX" - , "key index" - , "Get an element from a list by its index" - , COMMAND_GROUP_LIST - , "0.07" } - - , { "LINSERT" - , "key BEFORE|AFTER pivot value" - , "Insert an element before or after another element in a list" - , COMMAND_GROUP_LIST - , "2.1.1" } - - , { "LLEN" - , "key" - , "Get the length of a list" - , COMMAND_GROUP_LIST - , "0.07" } - - , { "LPOP" - , "key" - , "Remove and get the first element in a list" - , COMMAND_GROUP_LIST - , "0.07" } - - , { "LPUSH" - , "key value" - , "Prepend a value to a list" - , COMMAND_GROUP_LIST - , "0.07" } - - , { "LPUSHX" - , "key value" - , "Prepend a value to a list, only if the list exists" - , COMMAND_GROUP_LIST - , "2.1.1" } - - , { "LRANGE" - , "key start stop" - , "Get a range of elements from a list" - , COMMAND_GROUP_LIST - , "0.07" } - - , { "LREM" - , "key count value" - , "Remove elements from a list" - , COMMAND_GROUP_LIST - , "0.07" } - - , { "LSET" - , "key index value" - , "Set the value of an element in a list by its index" - , COMMAND_GROUP_LIST - , "0.07" } - - , { "LTRIM" - , "key start stop" - , "Trim a list to the specified range" - , COMMAND_GROUP_LIST - , "0.07" } - - , { "MGET" - , "(key)+" - , "Get the values of all the given keys" - , COMMAND_GROUP_STRING - , "0.07" } - - , { "MONITOR" - , "-" - , "Listen for all requests received by the server in real time" - , COMMAND_GROUP_SERVER - , "0.07" } - - , { "MOVE" - , "key db" - , "Move a key to another database" - , COMMAND_GROUP_GENERIC - , "0.07" } - - , { "MSET" - , "(key value)+" - , "Set multiple keys to multiple values" - , COMMAND_GROUP_STRING - , "1.001" } - - , { "MSETNX" - , "(key value)+" - , "Set multiple keys to multiple values, only if none of the keys exist" - , COMMAND_GROUP_STRING - , "1.001" } - - , { "MULTI" - , "-" - , "Mark the start of a transaction block" - , COMMAND_GROUP_TRANSACTIONS - , "1.1.95" } - - , { "PERSIST" - , "key" - , "Remove the expiration from a key" - , COMMAND_GROUP_GENERIC - , "2.1.2" } - - , { "PING" - , "-" - , "Ping the server" - , COMMAND_GROUP_CONNECTION - , "0.07" } - - , { "PSUBSCRIBE" - , "pattern" - , "Listen for messages published to channels matching the given patterns" - , COMMAND_GROUP_PUBSUB - , "1.3.8" } - - , { "PUBLISH" - , "channel message" - , "Post a message to a channel" - , COMMAND_GROUP_PUBSUB - , "1.3.8" } - - , { "PUNSUBSCRIBE" - , "(pattern)*" - , "Stop listening for messages posted to channels matching the given patterns" - , COMMAND_GROUP_PUBSUB - , "1.3.8" } - - , { "QUIT" - , "-" - , "Close the connection" - , COMMAND_GROUP_CONNECTION - , "0.07" } - - , { "RANDOMKEY" - , "-" - , "Return a random key from the keyspace" - , COMMAND_GROUP_GENERIC - , "0.07" } - - , { "RENAME" - , "old new" - , "Rename a key" - , COMMAND_GROUP_GENERIC - , "0.07" } - - , { "RENAMENX" - , "old new" - , "Rename a key, only if the new key does not exist" - , COMMAND_GROUP_GENERIC - , "0.07" } - - , { "RPOP" - , "key" - , "Remove and get the last element in a list" - , COMMAND_GROUP_LIST - , "0.07" } - - , { "RPOPLPUSH" - , "source destination" - , "Remove the last element in a list, append it to another list and return it" - , COMMAND_GROUP_LIST - , "1.1" } - - , { "RPUSH" - , "key value" - , "Append a value to a list" - , COMMAND_GROUP_LIST - , "0.07" } - - , { "RPUSHX" - , "key value" - , "Append a value to a list, only if the list exists" - , COMMAND_GROUP_LIST - , "2.1.1" } - - , { "SADD" - , "key member" - , "Add a member to a set" - , COMMAND_GROUP_SET - , "0.07" } - - , { "SAVE" - , "-" - , "Synchronously save the dataset to disk" - , COMMAND_GROUP_SERVER - , "0.07" } - - , { "SCARD" - , "key" - , "Get the number of members in a set" - , COMMAND_GROUP_SET - , "0.07" } - - , { "SDIFF" - , "(key)+" - , "Subtract multiple sets" - , COMMAND_GROUP_SET - , "0.100" } - - , { "SDIFFSTORE" - , "destination (key)+" - , "Subtract multiple sets and store the resulting set in a key" - , COMMAND_GROUP_SET - , "0.100" } - - , { "SELECT" - , "index" - , "Change the selected database for the current connection" - , COMMAND_GROUP_CONNECTION - , "0.07" } - - , { "SET" - , "key value" - , "Set the string value of a key" - , COMMAND_GROUP_STRING - , "0.07" } - - , { "SETEX" - , "key timestamp value" - , "Set the value and expiration of a key" - , COMMAND_GROUP_STRING - , "1.3.10" } - - , { "SETNX" - , "key value" - , "Set the value of a key, only if the key does not exist" - , COMMAND_GROUP_STRING - , "0.07" } - - , { "SHUTDOWN" - , "-" - , "Synchronously save the dataset to disk and then shut down the server" - , COMMAND_GROUP_SERVER - , "0.07" } - - , { "SINTER" - , "(key)+" - , "Intersect multiple sets" - , COMMAND_GROUP_SET - , "0.07" } - - , { "SINTERSTORE" - , "destination (key)+" - , "Intersect multiple sets and store the resulting set in a key" - , COMMAND_GROUP_SET - , "0.07" } - - , { "SISMEMBER" - , "key member" - , "Determine if a given value is a member of a set" - , COMMAND_GROUP_SET - , "0.07" } - - , { "SLAVEOF" - , "host port" - , "Make the server a slave of another instance, or promote it as master" - , COMMAND_GROUP_SERVER - , "0.100" } - - , { "SMEMBERS" - , "key" - , "Get all the members in a set" - , COMMAND_GROUP_SET - , "0.07" } - - , { "SMOVE" - , "source destination member" - , "Move a member from one set to another" - , COMMAND_GROUP_SET - , "0.091" } - - , { "SORT" - , "key (BY pattern)? (LIMIT start count)? (GET pattern)* (ASC|DESC)? (ALPHA)? (STORE destination)?" - , "Sort the elements in a list, set or sorted set" - , COMMAND_GROUP_GENERIC - , "0.07" } - - , { "SPOP" - , "key" - , "Remove and return a random member from a set" - , COMMAND_GROUP_SET - , "0.101" } - - , { "SRANDMEMBER" - , "key" - , "Get a random member from a set" - , COMMAND_GROUP_SET - , "1.001" } - - , { "SREM" - , "key member" - , "Remove a member from a set" - , COMMAND_GROUP_SET - , "0.07" } - - , { "STRLEN" - , "key" - , "Get the length of the value stored in a key" - , COMMAND_GROUP_STRING - , "2.1.2" } - - , { "SUBSCRIBE" - , "channel" - , "Listen for messages published to the given channels" - , COMMAND_GROUP_PUBSUB - , "1.3.8" } - - , { "SUBSTR" - , "key start stop" - , "Get a substring of the string stored at a key" - , COMMAND_GROUP_STRING - , "1.3.4" } - - , { "SUNION" - , "(key)+" - , "Add multiple sets" - , COMMAND_GROUP_SET - , "0.091" } - - , { "SUNIONSTORE" - , "destination (key)+" - , "Add multiple sets and store the resulting set in a key" - , COMMAND_GROUP_SET - , "0.091" } - - , { "SYNC" - , "-" - , "Internal command used for replication" - , COMMAND_GROUP_SERVER - , "0.07" } - - , { "TTL" - , "key" - , "Get the time to live for a key" - , COMMAND_GROUP_GENERIC - , "0.100" } - - , { "TYPE" - , "key" - , "Determine the type stored at key" - , COMMAND_GROUP_GENERIC - , "0.07" } - - , { "UNSUBSCRIBE" - , "(channel)*" - , "Stop listening for messages posted to the given channels" - , COMMAND_GROUP_PUBSUB - , "1.3.8" } - - , { "UNWATCH" - , "-" - , "Forget about all watched keys" - , COMMAND_GROUP_TRANSACTIONS - , "2.1.0" } - - , { "WATCH" - , "(key)+" - , "Watch the given keys to determine execution of the MULTI/EXEC block" - , COMMAND_GROUP_TRANSACTIONS - , "2.1.0" } - - , { "ZADD" - , "key score member" - , "Add a member to a sorted set, or update its score if it already exists" - , COMMAND_GROUP_SORTED_SET - , "1.1" } - - , { "ZCARD" - , "key" - , "Get the number of members in a sorted set" - , COMMAND_GROUP_SORTED_SET - , "1.1" } - - , { "ZCOUNT" - , "key min max" - , "Count the members in a sorted set with scores within the given values" - , COMMAND_GROUP_SORTED_SET - , "1.3.3" } - - , { "ZINCRBY" - , "key increment member" - , "Increment the score of a member in a sorted set" - , COMMAND_GROUP_SORTED_SET - , "1.1" } - - , { "ZINTERSTORE" - , "destination (key)+ (WEIGHTS weight)? (AGGREGATE SUM|MIN|MAX)?" - , "Intersect multiple sorted sets and store the resulting sorted set in a new key" - , COMMAND_GROUP_SORTED_SET - , "1.3.10" } - - , { "ZRANGE" - , "key start stop" - , "Return a range of members in a sorted set, by index" - , COMMAND_GROUP_SORTED_SET - , "1.1" } - - , { "ZRANGEBYSCORE" - , "key min max" - , "Return a range of members in a sorted set, by score" - , COMMAND_GROUP_SORTED_SET - , "1.050" } - - , { "ZRANK" - , "key member" - , "Determine the index of a member in a sorted set" - , COMMAND_GROUP_SORTED_SET - , "1.3.4" } - - , { "ZREM" - , "key member" - , "Remove a member from a sorted set" - , COMMAND_GROUP_SORTED_SET - , "1.1" } - - , { "ZREMRANGEBYRANK" - , "key start stop" - , "Remove all members in a sorted set within the given indexes" - , COMMAND_GROUP_SORTED_SET - , "1.3.4" } - - , { "ZREMRANGEBYSCORE" - , "key min max" - , "Remove all members in a sorted set within the given scores" - , COMMAND_GROUP_SORTED_SET - , "1.1" } - - , { "ZREVRANGE" - , "key start stop" - , "Return a range of members in a sorted set, by index, with scores ordered from high to low" - , COMMAND_GROUP_SORTED_SET - , "1.1" } - - , { "ZREVRANK" - , "key member" - , "Determine the index of a member in a sorted set, with scores ordered from high to low" - , COMMAND_GROUP_SORTED_SET - , "1.3.4" } - - , { "ZSCORE" - , "key member" - , "Get the score associated with the given member in a sorted set" - , COMMAND_GROUP_SORTED_SET - , "1.1" } - - , { "ZUNIONSTORE" - , "destination (key)+ (WEIGHTS weight)? (AGGREGATE SUM|MIN|MAX)?" - , "Add multiple sorted sets and store the resulting sorted set in a new key" - , COMMAND_GROUP_SORTED_SET - , "1.3.10" } }; /* diff --git a/utils/generate-command-help.rb b/utils/generate-command-help.rb index 250a2159e..4b2f25a15 100755 --- a/utils/generate-command-help.rb +++ b/utils/generate-command-help.rb @@ -1,56 +1,59 @@ #!/usr/bin/env ruby -require 'net/http' -require 'net/https' -require 'json' -require 'uri' - -dest = ARGV[0] -tmpl = File.read './utils/help.h' - -url = URI.parse 'https://github.com/antirez/redis-doc/raw/master/commands.json' -client = Net::HTTP.new url.host, url.port -client.use_ssl = true -res = client.get url.path - def argument arg - name = arg['name'].is_a?(Array) ? arg['name'].join(' ') : arg['name'] - name = arg['enum'].join '|' if 'enum' == arg['type'] - name = arg['command'] + ' ' + name if arg['command'] - if arg['multiple'] - name = "(#{name})" - name += arg['optional'] ? '*' : '+' - elsif arg['optional'] - name = "(#{name})?" + name = arg["name"].is_a?(Array) ? arg["name"].join(" ") : arg["name"] + name = arg["enum"].join "|" if "enum" == arg["type"] + name = arg["command"] + " " + name if arg["command"] + if arg["multiple"] + name = "#{name} [#{name} ...]" + end + if arg["optional"] + name = "[#{name}]" end name end def arguments command - return '-' unless command['arguments'] - command['arguments'].map do |arg| + return "-" unless command["arguments"] + command["arguments"].map do |arg| argument arg - end.join ' ' + end.join " " end -case res -when Net::HTTPSuccess - first = true - commands = JSON.parse(res.body) - c = commands.map do |key, command| - buf = if first - first = false - ' ' - else - "\n ," - end - buf += " { \"#{key}\"\n" + - " , \"#{arguments(command)}\"\n" + - " , \"#{command['summary']}\"\n" + - " , COMMAND_GROUP_#{command['group'].upcase}\n" + - " , \"#{command['since']}\" }" - end.join("\n") - puts "\n// Auto-generated, do not edit.\n" + tmpl.sub('__COMMANDS__', c) -else - res.error! -end \ No newline at end of file +def commands + return @commands if @commands + + require "net/http" + require "net/https" + require "json" + require "uri" + + url = URI.parse "https://github.com/antirez/redis-doc/raw/master/commands.json" + client = Net::HTTP.new url.host, url.port + client.use_ssl = true + response = client.get url.path + if response.is_a?(Net::HTTPSuccess) + @commands = JSON.parse(response.body) + else + response.error! + end +end + +def generate_commands + commands.to_a.sort do |x,y| + x[0] <=> y[0] + end.map do |key, command| + <<-SPEC +{ "#{key}", + "#{arguments(command)}", + "#{command["summary"]}", + COMMAND_GROUP_#{command["group"].upcase}, + "#{command["since"]}" } + SPEC + end.join(", ") +end + +# Write to stdout +tmpl = File.read "./utils/help.h" +puts "\n// Auto-generated, do not edit.\n" + tmpl.sub("__COMMANDS__", generate_commands) + From a2a69d5803d05ce9ccd2d911389b8aa28239dfba Mon Sep 17 00:00:00 2001 From: Pieter Noordhuis Date: Sun, 28 Nov 2010 21:37:19 +0100 Subject: [PATCH 3/8] Refactor help-related code into redis-cli.c --- src/help.h | 823 +++++++++++++++------------------ src/redis-cli.c | 61 ++- utils/generate-command-help.rb | 62 ++- utils/help.h | 119 ----- 4 files changed, 482 insertions(+), 583 deletions(-) delete mode 100644 utils/help.h diff --git a/src/help.h b/src/help.h index ba9b299a9..121d9dfaf 100644 --- a/src/help.h +++ b/src/help.h @@ -1,701 +1,608 @@ +/* Automatically generated by utils/generate-command-help.rb, do not edit. */ -// Auto-generated, do not edit. +#ifndef __REDIS_HELP_H +#define __REDIS_HELP_H -#include -#include - -/* - * List command groups. - */ - -#define GROUPS \ - G(UNKNOWN, "unknown") \ - G(SET, "set") \ - G(LIST, "list") \ - G(HASH, "hash") \ - G(GENERIC, "generic") \ - G(PUBSUB, "pubsub") \ - G(STRING, "string") \ - G(SERVER, "server") \ - G(CONNECTION, "connection") \ - G(TRANSACTIONS, "transactions") \ - G(SORTED_SET, "sorted_set") - -/* - * Command group types. - */ - -typedef enum { - #define G(GROUP, _) COMMAND_GROUP_##GROUP, - GROUPS - #undef G - COMMAND_GROUP_LENGTH -} command_group_type_t; - -/* - * Command group type names. - */ - -static char *command_group_type_names[] = { - #define G(_, STR) STR, - GROUPS - #undef G +static char *commandGroups[] = { + "generic", + "string", + "list", + "set", + "sorted_set", + "hash", + "pubsub", + "transactions", + "connection", + "server" }; -/* - * Command help struct. - */ - -struct command_help { +struct commandHelp { char *name; char *params; char *summary; - command_group_type_t group; + int group; char *since; -} command_help[] = { - { "APPEND", +} commandHelp[] = { + { "APPEND", "key value", "Append a value to a key", - COMMAND_GROUP_STRING, - "1.3.3" } -, { "AUTH", + 1, + "1.3.3" }, + { "AUTH", "password", "Authenticate to the server", - COMMAND_GROUP_CONNECTION, - "0.08" } -, { "BGREWRITEAOF", + 8, + "0.08" }, + { "BGREWRITEAOF", "-", "Asynchronously rewrite the append-only file", - COMMAND_GROUP_SERVER, - "1.07" } -, { "BGSAVE", + 9, + "1.07" }, + { "BGSAVE", "-", "Asynchronously save the dataset to disk", - COMMAND_GROUP_SERVER, - "0.07" } -, { "BLPOP", + 9, + "0.07" }, + { "BLPOP", "key [key ...] timeout", "Remove and get the first element in a list, or block until one is available", - COMMAND_GROUP_LIST, - "1.3.1" } -, { "BRPOP", + 2, + "1.3.1" }, + { "BRPOP", "key [key ...] timeout", "Remove and get the last element in a list, or block until one is available", - COMMAND_GROUP_LIST, - "1.3.1" } -, { "CONFIG GET", + 2, + "1.3.1" }, + { "CONFIG GET", "parameter", "Get the value of a configuration parameter", - COMMAND_GROUP_SERVER, - "2.0" } -, { "CONFIG SET", + 9, + "2.0" }, + { "CONFIG SET", "parameter value", "Set a configuration parameter to the given value", - COMMAND_GROUP_SERVER, - "2.0" } -, { "DBSIZE", + 9, + "2.0" }, + { "DBSIZE", "-", "Return the number of keys in the selected database", - COMMAND_GROUP_SERVER, - "0.07" } -, { "DEBUG OBJECT", + 9, + "0.07" }, + { "DEBUG OBJECT", "key", "Get debugging information about a key", - COMMAND_GROUP_SERVER, - "0.101" } -, { "DEBUG SEGFAULT", + 9, + "0.101" }, + { "DEBUG SEGFAULT", "-", "Make the server crash", - COMMAND_GROUP_SERVER, - "0.101" } -, { "DECR", + 9, + "0.101" }, + { "DECR", "key decrement", "Decrement the integer value of a key by one", - COMMAND_GROUP_STRING, - "0.07" } -, { "DECRBY", + 1, + "0.07" }, + { "DECRBY", "key decrement", "Decrement the integer value of a key by the given number", - COMMAND_GROUP_STRING, - "0.07" } -, { "DEL", + 1, + "0.07" }, + { "DEL", "key [key ...]", "Delete a key", - COMMAND_GROUP_GENERIC, - "0.07" } -, { "DISCARD", + 0, + "0.07" }, + { "DISCARD", "-", "Discard all commands issued after MULTI", - COMMAND_GROUP_TRANSACTIONS, - "1.3.3" } -, { "ECHO", + 7, + "1.3.3" }, + { "ECHO", "message", "Echo the given string", - COMMAND_GROUP_CONNECTION, - "0.07" } -, { "EXEC", + 8, + "0.07" }, + { "EXEC", "-", "Execute all commands issued after MULTI", - COMMAND_GROUP_TRANSACTIONS, - "1.1.95" } -, { "EXISTS", + 7, + "1.1.95" }, + { "EXISTS", "key", "Determine if a key exists", - COMMAND_GROUP_SERVER, - "0.07" } -, { "EXPIRE", + 9, + "0.07" }, + { "EXPIRE", "key seconds", "Set a key's time to live in seconds", - COMMAND_GROUP_GENERIC, - "0.09" } -, { "EXPIREAT", + 0, + "0.09" }, + { "EXPIREAT", "key timestamp", "Set the expiration for a key as a UNIX timestamp", - COMMAND_GROUP_GENERIC, - "1.1" } -, { "FLUSHALL", + 0, + "1.1" }, + { "FLUSHALL", "-", "Remove all keys from all databases", - COMMAND_GROUP_SERVER, - "0.07" } -, { "FLUSHDB", + 9, + "0.07" }, + { "FLUSHDB", "-", "Remove all keys from the current database", - COMMAND_GROUP_SERVER, - "0.07" } -, { "GET", + 9, + "0.07" }, + { "GET", "key", "Get the value of a key", - COMMAND_GROUP_STRING, - "0.07" } -, { "GETSET", + 1, + "0.07" }, + { "GETSET", "key value", "Set the string value of a key and return its old value", - COMMAND_GROUP_STRING, - "0.091" } -, { "HDEL", + 1, + "0.091" }, + { "HDEL", "key field", "Delete a hash field", - COMMAND_GROUP_HASH, - "1.3.10" } -, { "HEXISTS", + 5, + "1.3.10" }, + { "HEXISTS", "key field", "Determine if a hash field exists", - COMMAND_GROUP_HASH, - "1.3.10" } -, { "HGET", + 5, + "1.3.10" }, + { "HGET", "key field", "Get the value of a hash field", - COMMAND_GROUP_HASH, - "1.3.10" } -, { "HGETALL", + 5, + "1.3.10" }, + { "HGETALL", "key", "Get all the fields and values in a hash", - COMMAND_GROUP_HASH, - "1.3.10" } -, { "HINCRBY", + 5, + "1.3.10" }, + { "HINCRBY", "key field increment", "Increment the integer value of a hash field by the given number", - COMMAND_GROUP_HASH, - "1.3.10" } -, { "HKEYS", + 5, + "1.3.10" }, + { "HKEYS", "key", "Get all the fields in a hash", - COMMAND_GROUP_HASH, - "1.3.10" } -, { "HLEN", + 5, + "1.3.10" }, + { "HLEN", "key", "Get the number of fields in a hash", - COMMAND_GROUP_HASH, - "1.3.10" } -, { "HMGET", + 5, + "1.3.10" }, + { "HMGET", "key field [field ...]", "Get the values of all the given hash fields", - COMMAND_GROUP_HASH, - "1.3.10" } -, { "HMSET", + 5, + "1.3.10" }, + { "HMSET", "key field value [field value ...]", "Set multiple hash fields to multiple values", - COMMAND_GROUP_HASH, - "1.3.8" } -, { "HSET", + 5, + "1.3.8" }, + { "HSET", "key field value", "Set the string value of a hash field", - COMMAND_GROUP_HASH, - "1.3.10" } -, { "HSETNX", + 5, + "1.3.10" }, + { "HSETNX", "key field value", "Set the value of a hash field, only if the field does not exist", - COMMAND_GROUP_HASH, - "1.3.8" } -, { "HVALS", + 5, + "1.3.8" }, + { "HVALS", "key", "Get all the values in a hash", - COMMAND_GROUP_HASH, - "1.3.10" } -, { "INCR", + 5, + "1.3.10" }, + { "INCR", "key", "Increment the integer value of a key by one", - COMMAND_GROUP_STRING, - "0.07" } -, { "INCRBY", + 1, + "0.07" }, + { "INCRBY", "key increment", "Increment the integer value of a key by the given number", - COMMAND_GROUP_STRING, - "0.07" } -, { "INFO", + 1, + "0.07" }, + { "INFO", "-", "Get information and statistics about the server", - COMMAND_GROUP_SERVER, - "0.07" } -, { "KEYS", + 9, + "0.07" }, + { "KEYS", "pattern", "Find all keys matching the given pattern", - COMMAND_GROUP_GENERIC, - "0.07" } -, { "LASTSAVE", + 0, + "0.07" }, + { "LASTSAVE", "-", "Get the UNIX time stamp of the last successful save to disk", - COMMAND_GROUP_SERVER, - "0.07" } -, { "LINDEX", + 9, + "0.07" }, + { "LINDEX", "key index", "Get an element from a list by its index", - COMMAND_GROUP_LIST, - "0.07" } -, { "LINSERT", + 2, + "0.07" }, + { "LINSERT", "key BEFORE|AFTER pivot value", "Insert an element before or after another element in a list", - COMMAND_GROUP_LIST, - "2.1.1" } -, { "LLEN", + 2, + "2.1.1" }, + { "LLEN", "key", "Get the length of a list", - COMMAND_GROUP_LIST, - "0.07" } -, { "LPOP", + 2, + "0.07" }, + { "LPOP", "key", "Remove and get the first element in a list", - COMMAND_GROUP_LIST, - "0.07" } -, { "LPUSH", + 2, + "0.07" }, + { "LPUSH", "key value", "Prepend a value to a list", - COMMAND_GROUP_LIST, - "0.07" } -, { "LPUSHX", + 2, + "0.07" }, + { "LPUSHX", "key value", "Prepend a value to a list, only if the list exists", - COMMAND_GROUP_LIST, - "2.1.1" } -, { "LRANGE", + 2, + "2.1.1" }, + { "LRANGE", "key start stop", "Get a range of elements from a list", - COMMAND_GROUP_LIST, - "0.07" } -, { "LREM", + 2, + "0.07" }, + { "LREM", "key count value", "Remove elements from a list", - COMMAND_GROUP_LIST, - "0.07" } -, { "LSET", + 2, + "0.07" }, + { "LSET", "key index value", "Set the value of an element in a list by its index", - COMMAND_GROUP_LIST, - "0.07" } -, { "LTRIM", + 2, + "0.07" }, + { "LTRIM", "key start stop", "Trim a list to the specified range", - COMMAND_GROUP_LIST, - "0.07" } -, { "MGET", + 2, + "0.07" }, + { "MGET", "key [key ...]", "Get the values of all the given keys", - COMMAND_GROUP_STRING, - "0.07" } -, { "MONITOR", + 1, + "0.07" }, + { "MONITOR", "-", "Listen for all requests received by the server in real time", - COMMAND_GROUP_SERVER, - "0.07" } -, { "MOVE", + 9, + "0.07" }, + { "MOVE", "key db", "Move a key to another database", - COMMAND_GROUP_GENERIC, - "0.07" } -, { "MSET", + 0, + "0.07" }, + { "MSET", "key value [key value ...]", "Set multiple keys to multiple values", - COMMAND_GROUP_STRING, - "1.001" } -, { "MSETNX", + 1, + "1.001" }, + { "MSETNX", "key value [key value ...]", "Set multiple keys to multiple values, only if none of the keys exist", - COMMAND_GROUP_STRING, - "1.001" } -, { "MULTI", + 1, + "1.001" }, + { "MULTI", "-", "Mark the start of a transaction block", - COMMAND_GROUP_TRANSACTIONS, - "1.1.95" } -, { "PERSIST", + 7, + "1.1.95" }, + { "PERSIST", "key", "Remove the expiration from a key", - COMMAND_GROUP_GENERIC, - "2.1.2" } -, { "PING", + 0, + "2.1.2" }, + { "PING", "-", "Ping the server", - COMMAND_GROUP_CONNECTION, - "0.07" } -, { "PSUBSCRIBE", + 8, + "0.07" }, + { "PSUBSCRIBE", "pattern", "Listen for messages published to channels matching the given patterns", - COMMAND_GROUP_PUBSUB, - "1.3.8" } -, { "PUBLISH", + 6, + "1.3.8" }, + { "PUBLISH", "channel message", "Post a message to a channel", - COMMAND_GROUP_PUBSUB, - "1.3.8" } -, { "PUNSUBSCRIBE", + 6, + "1.3.8" }, + { "PUNSUBSCRIBE", "[pattern [pattern ...]]", "Stop listening for messages posted to channels matching the given patterns", - COMMAND_GROUP_PUBSUB, - "1.3.8" } -, { "QUIT", + 6, + "1.3.8" }, + { "QUIT", "-", "Close the connection", - COMMAND_GROUP_CONNECTION, - "0.07" } -, { "RANDOMKEY", + 8, + "0.07" }, + { "RANDOMKEY", "-", "Return a random key from the keyspace", - COMMAND_GROUP_GENERIC, - "0.07" } -, { "RENAME", + 0, + "0.07" }, + { "RENAME", "old new", "Rename a key", - COMMAND_GROUP_GENERIC, - "0.07" } -, { "RENAMENX", + 0, + "0.07" }, + { "RENAMENX", "old new", "Rename a key, only if the new key does not exist", - COMMAND_GROUP_GENERIC, - "0.07" } -, { "RPOP", + 0, + "0.07" }, + { "RPOP", "key", "Remove and get the last element in a list", - COMMAND_GROUP_LIST, - "0.07" } -, { "RPOPLPUSH", + 2, + "0.07" }, + { "RPOPLPUSH", "source destination", "Remove the last element in a list, append it to another list and return it", - COMMAND_GROUP_LIST, - "1.1" } -, { "RPUSH", + 2, + "1.1" }, + { "RPUSH", "key value", "Append a value to a list", - COMMAND_GROUP_LIST, - "0.07" } -, { "RPUSHX", + 2, + "0.07" }, + { "RPUSHX", "key value", "Append a value to a list, only if the list exists", - COMMAND_GROUP_LIST, - "2.1.1" } -, { "SADD", + 2, + "2.1.1" }, + { "SADD", "key member", "Add a member to a set", - COMMAND_GROUP_SET, - "0.07" } -, { "SAVE", + 3, + "0.07" }, + { "SAVE", "-", "Synchronously save the dataset to disk", - COMMAND_GROUP_SERVER, - "0.07" } -, { "SCARD", + 9, + "0.07" }, + { "SCARD", "key", "Get the number of members in a set", - COMMAND_GROUP_SET, - "0.07" } -, { "SDIFF", + 3, + "0.07" }, + { "SDIFF", "key [key ...]", "Subtract multiple sets", - COMMAND_GROUP_SET, - "0.100" } -, { "SDIFFSTORE", + 3, + "0.100" }, + { "SDIFFSTORE", "destination key [key ...]", "Subtract multiple sets and store the resulting set in a key", - COMMAND_GROUP_SET, - "0.100" } -, { "SELECT", + 3, + "0.100" }, + { "SELECT", "index", "Change the selected database for the current connection", - COMMAND_GROUP_CONNECTION, - "0.07" } -, { "SET", + 8, + "0.07" }, + { "SET", "key value", "Set the string value of a key", - COMMAND_GROUP_STRING, - "0.07" } -, { "SETEX", + 1, + "0.07" }, + { "SETEX", "key timestamp value", "Set the value and expiration of a key", - COMMAND_GROUP_STRING, - "1.3.10" } -, { "SETNX", + 1, + "1.3.10" }, + { "SETNX", "key value", "Set the value of a key, only if the key does not exist", - COMMAND_GROUP_STRING, - "0.07" } -, { "SHUTDOWN", + 1, + "0.07" }, + { "SHUTDOWN", "-", "Synchronously save the dataset to disk and then shut down the server", - COMMAND_GROUP_SERVER, - "0.07" } -, { "SINTER", + 9, + "0.07" }, + { "SINTER", "key [key ...]", "Intersect multiple sets", - COMMAND_GROUP_SET, - "0.07" } -, { "SINTERSTORE", + 3, + "0.07" }, + { "SINTERSTORE", "destination key [key ...]", "Intersect multiple sets and store the resulting set in a key", - COMMAND_GROUP_SET, - "0.07" } -, { "SISMEMBER", + 3, + "0.07" }, + { "SISMEMBER", "key member", "Determine if a given value is a member of a set", - COMMAND_GROUP_SET, - "0.07" } -, { "SLAVEOF", + 3, + "0.07" }, + { "SLAVEOF", "host port", "Make the server a slave of another instance, or promote it as master", - COMMAND_GROUP_SERVER, - "0.100" } -, { "SMEMBERS", + 9, + "0.100" }, + { "SMEMBERS", "key", "Get all the members in a set", - COMMAND_GROUP_SET, - "0.07" } -, { "SMOVE", + 3, + "0.07" }, + { "SMOVE", "source destination member", "Move a member from one set to another", - COMMAND_GROUP_SET, - "0.091" } -, { "SORT", + 3, + "0.091" }, + { "SORT", "key [BY pattern] [LIMIT start count] [GET pattern [GET pattern ...]] [ASC|DESC] [ALPHA] [STORE destination]", "Sort the elements in a list, set or sorted set", - COMMAND_GROUP_GENERIC, - "0.07" } -, { "SPOP", + 0, + "0.07" }, + { "SPOP", "key", "Remove and return a random member from a set", - COMMAND_GROUP_SET, - "0.101" } -, { "SRANDMEMBER", + 3, + "0.101" }, + { "SRANDMEMBER", "key", "Get a random member from a set", - COMMAND_GROUP_SET, - "1.001" } -, { "SREM", + 3, + "1.001" }, + { "SREM", "key member", "Remove a member from a set", - COMMAND_GROUP_SET, - "0.07" } -, { "STRLEN", + 3, + "0.07" }, + { "STRLEN", "key", "Get the length of the value stored in a key", - COMMAND_GROUP_STRING, - "2.1.2" } -, { "SUBSCRIBE", + 1, + "2.1.2" }, + { "SUBSCRIBE", "channel", "Listen for messages published to the given channels", - COMMAND_GROUP_PUBSUB, - "1.3.8" } -, { "SUBSTR", + 6, + "1.3.8" }, + { "SUBSTR", "key start stop", "Get a substring of the string stored at a key", - COMMAND_GROUP_STRING, - "1.3.4" } -, { "SUNION", + 1, + "1.3.4" }, + { "SUNION", "key [key ...]", "Add multiple sets", - COMMAND_GROUP_SET, - "0.091" } -, { "SUNIONSTORE", + 3, + "0.091" }, + { "SUNIONSTORE", "destination key [key ...]", "Add multiple sets and store the resulting set in a key", - COMMAND_GROUP_SET, - "0.091" } -, { "SYNC", + 3, + "0.091" }, + { "SYNC", "-", "Internal command used for replication", - COMMAND_GROUP_SERVER, - "0.07" } -, { "TTL", + 9, + "0.07" }, + { "TTL", "key", "Get the time to live for a key", - COMMAND_GROUP_GENERIC, - "0.100" } -, { "TYPE", + 0, + "0.100" }, + { "TYPE", "key", "Determine the type stored at key", - COMMAND_GROUP_GENERIC, - "0.07" } -, { "UNSUBSCRIBE", + 0, + "0.07" }, + { "UNSUBSCRIBE", "[channel [channel ...]]", "Stop listening for messages posted to the given channels", - COMMAND_GROUP_PUBSUB, - "1.3.8" } -, { "UNWATCH", + 6, + "1.3.8" }, + { "UNWATCH", "-", "Forget about all watched keys", - COMMAND_GROUP_TRANSACTIONS, - "2.1.0" } -, { "WATCH", + 7, + "2.1.0" }, + { "WATCH", "key [key ...]", "Watch the given keys to determine execution of the MULTI/EXEC block", - COMMAND_GROUP_TRANSACTIONS, - "2.1.0" } -, { "ZADD", + 7, + "2.1.0" }, + { "ZADD", "key score member", "Add a member to a sorted set, or update its score if it already exists", - COMMAND_GROUP_SORTED_SET, - "1.1" } -, { "ZCARD", + 4, + "1.1" }, + { "ZCARD", "key", "Get the number of members in a sorted set", - COMMAND_GROUP_SORTED_SET, - "1.1" } -, { "ZCOUNT", + 4, + "1.1" }, + { "ZCOUNT", "key min max", "Count the members in a sorted set with scores within the given values", - COMMAND_GROUP_SORTED_SET, - "1.3.3" } -, { "ZINCRBY", + 4, + "1.3.3" }, + { "ZINCRBY", "key increment member", "Increment the score of a member in a sorted set", - COMMAND_GROUP_SORTED_SET, - "1.1" } -, { "ZINTERSTORE", + 4, + "1.1" }, + { "ZINTERSTORE", "destination key [key ...] [WEIGHTS weight] [AGGREGATE SUM|MIN|MAX]", "Intersect multiple sorted sets and store the resulting sorted set in a new key", - COMMAND_GROUP_SORTED_SET, - "1.3.10" } -, { "ZRANGE", + 4, + "1.3.10" }, + { "ZRANGE", "key start stop", "Return a range of members in a sorted set, by index", - COMMAND_GROUP_SORTED_SET, - "1.1" } -, { "ZRANGEBYSCORE", + 4, + "1.1" }, + { "ZRANGEBYSCORE", "key min max", "Return a range of members in a sorted set, by score", - COMMAND_GROUP_SORTED_SET, - "1.050" } -, { "ZRANK", + 4, + "1.050" }, + { "ZRANK", "key member", "Determine the index of a member in a sorted set", - COMMAND_GROUP_SORTED_SET, - "1.3.4" } -, { "ZREM", + 4, + "1.3.4" }, + { "ZREM", "key member", "Remove a member from a sorted set", - COMMAND_GROUP_SORTED_SET, - "1.1" } -, { "ZREMRANGEBYRANK", + 4, + "1.1" }, + { "ZREMRANGEBYRANK", "key start stop", "Remove all members in a sorted set within the given indexes", - COMMAND_GROUP_SORTED_SET, - "1.3.4" } -, { "ZREMRANGEBYSCORE", + 4, + "1.3.4" }, + { "ZREMRANGEBYSCORE", "key min max", "Remove all members in a sorted set within the given scores", - COMMAND_GROUP_SORTED_SET, - "1.1" } -, { "ZREVRANGE", + 4, + "1.1" }, + { "ZREVRANGE", "key start stop", "Return a range of members in a sorted set, by index, with scores ordered from high to low", - COMMAND_GROUP_SORTED_SET, - "1.1" } -, { "ZREVRANK", + 4, + "1.1" }, + { "ZREVRANK", "key member", "Determine the index of a member in a sorted set, with scores ordered from high to low", - COMMAND_GROUP_SORTED_SET, - "1.3.4" } -, { "ZSCORE", + 4, + "1.3.4" }, + { "ZSCORE", "key member", "Get the score associated with the given member in a sorted set", - COMMAND_GROUP_SORTED_SET, - "1.1" } -, { "ZUNIONSTORE", + 4, + "1.1" }, + { "ZUNIONSTORE", "destination key [key ...] [WEIGHTS weight] [AGGREGATE SUM|MIN|MAX]", "Add multiple sorted sets and store the resulting sorted set in a new key", - COMMAND_GROUP_SORTED_SET, + 4, "1.3.10" } - }; -/* - * Output command help to stdout. - */ - -static void -output_command_help(struct command_help *help) { - printf("\n \x1b[1m%s\x1b[0m \x1b[90m%s\x1b[0m\n", help->name, help->params); - printf(" \x1b[33msummary:\x1b[0m %s\n", help->summary); - printf(" \x1b[33msince:\x1b[0m %s\n", help->since); - printf(" \x1b[33mgroup:\x1b[0m %s\n", command_group_type_names[help->group]); -} - -/* - * Return command group type by name string. - */ - -static command_group_type_t -command_group_type_by_name(const char *name) { - for (int i = 0; i < COMMAND_GROUP_LENGTH; ++i) { - const char *group = command_group_type_names[i]; - if (0 == strcasecmp(name, group)) return i; - } - return 0; -} - -/* - * Output group names. - */ - -static void -output_group_help() { - for (int i = 0; i < COMMAND_GROUP_LENGTH; ++i) { - if (COMMAND_GROUP_UNKNOWN == i) continue; - const char *group = command_group_type_names[i]; - printf(" \x1b[90m-\x1b[0m %s\n", group); - } -} - -/* - * Output all command help, filtering by group or command name. - */ - -static void -output_help(int argc, const char **argv) { - int len = sizeof(command_help) / sizeof(struct command_help); - - if (argc && 0 == strcasecmp("groups", argv[0])) { - output_group_help(); - return; - } - - command_group_type_t group = argc - ? command_group_type_by_name(argv[0]) - : COMMAND_GROUP_UNKNOWN; - - for (int i = 0; i < len; ++i) { - struct command_help help = command_help[i]; - if (argc && !group && 0 != strcasecmp(help.name, argv[0])) continue; - if (group && group != help.group) continue; - output_command_help(&help); - } - puts(""); -} +#endif diff --git a/src/redis-cli.c b/src/redis-cli.c index 5f01a936e..865f09313 100644 --- a/src/redis-cli.c +++ b/src/redis-cli.c @@ -84,6 +84,65 @@ static long long mstime(void) { return mst; } +/*------------------------------------------------------------------------------ + * Help functions + *--------------------------------------------------------------------------- */ + +/* Output command help to stdout. */ +static void outputCommandHelp(struct commandHelp *help) { + printf("\n \x1b[1m%s\x1b[0m \x1b[90m%s\x1b[0m\n", help->name, help->params); + printf(" \x1b[33msummary:\x1b[0m %s\n", help->summary); + printf(" \x1b[33msince:\x1b[0m %s\n", help->since); + printf(" \x1b[33mgroup:\x1b[0m %s\n", commandGroups[help->group]); +} + +/* Return command group type by name string. */ +static int commandGroupIndex(const char *name) { + int i, len = sizeof(commandGroups)/sizeof(char*); + for (i = 0; i < len; i++) + if (strcasecmp(name, commandGroups[i]) == 0) + return i; + return -1; +} + +/* 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. */ +static void outputHelp(int argc, char **argv) { + int i, len = sizeof(commandHelp) / sizeof(struct commandHelp); + int group; + struct commandHelp *help; + + if (argc && strcasecmp("groups", argv[0]) == 0) { + outputGroupHelp(); + return; + } + + group = argc ? commandGroupIndex(argv[0]) : -1; + for (i = 0; i < len; i++) { + help = &commandHelp[i]; + if (group == -1) { + if (argc) { + if (strcasecmp(help->name, argv[0]) == 0) { + outputCommandHelp(help); + } + } else { + outputCommandHelp(help); + } + } else { + if (group == help->group) { + outputCommandHelp(help); + } + } + } + puts(""); +} + /*------------------------------------------------------------------------------ * Networking / parsing *--------------------------------------------------------------------------- */ @@ -260,7 +319,7 @@ static int cliSendCommand(int argc, char **argv, int repeat) { config.raw_output = !strcasecmp(command,"info"); if (!strcasecmp(command,"help")) { - output_help(--argc, ++argv); + outputHelp(--argc, ++argv); return REDIS_OK; } if (!strcasecmp(command,"shutdown")) config.shutdown = 1; diff --git a/utils/generate-command-help.rb b/utils/generate-command-help.rb index 4b2f25a15..f730eaf10 100755 --- a/utils/generate-command-help.rb +++ b/utils/generate-command-help.rb @@ -1,5 +1,24 @@ #!/usr/bin/env ruby +GROUPS = [ + "generic", + "string", + "list", + "set", + "sorted_set", + "hash", + "pubsub", + "transactions", + "connection", + "server" +].freeze + +GROUPS_BY_NAME = Hash[* + GROUPS.each_with_index.map do |n,i| + [n,i] + end.flatten +].freeze + def argument arg name = arg["name"].is_a?(Array) ? arg["name"].join(" ") : arg["name"] name = arg["enum"].join "|" if "enum" == arg["type"] @@ -39,21 +58,54 @@ def commands end end +def generate_groups + GROUPS.map do |n| + "\"#{n}\"" + end.join(",\n "); +end + def generate_commands commands.to_a.sort do |x,y| x[0] <=> y[0] end.map do |key, command| - <<-SPEC + group = GROUPS_BY_NAME[command["group"]] + if group.nil? + STDERR.puts "Please update groups array in #{__FILE__}" + raise "Unknown group #{command["group"]}" + end + + ret = <<-SPEC { "#{key}", "#{arguments(command)}", "#{command["summary"]}", - COMMAND_GROUP_#{command["group"].upcase}, + #{group}, "#{command["since"]}" } SPEC - end.join(", ") + ret.strip + end.join(",\n ") end # Write to stdout -tmpl = File.read "./utils/help.h" -puts "\n// Auto-generated, do not edit.\n" + tmpl.sub("__COMMANDS__", generate_commands) +puts <<-HELP_H +/* Automatically generated by #{__FILE__}, do not edit. */ + +#ifndef __REDIS_HELP_H +#define __REDIS_HELP_H + +static char *commandGroups[] = { + #{generate_groups} +}; + +struct commandHelp { + char *name; + char *params; + char *summary; + int group; + char *since; +} commandHelp[] = { + #{generate_commands} +}; + +#endif +HELP_H diff --git a/utils/help.h b/utils/help.h deleted file mode 100644 index dc7f270d9..000000000 --- a/utils/help.h +++ /dev/null @@ -1,119 +0,0 @@ - -#include -#include - -/* - * List command groups. - */ - -#define GROUPS \ - G(UNKNOWN, "unknown") \ - G(SET, "set") \ - G(LIST, "list") \ - G(HASH, "hash") \ - G(GENERIC, "generic") \ - G(PUBSUB, "pubsub") \ - G(STRING, "string") \ - G(SERVER, "server") \ - G(CONNECTION, "connection") \ - G(TRANSACTIONS, "transactions") \ - G(SORTED_SET, "sorted_set") - -/* - * Command group types. - */ - -typedef enum { - #define G(GROUP, _) COMMAND_GROUP_##GROUP, - GROUPS - #undef G - COMMAND_GROUP_LENGTH -} command_group_type_t; - -/* - * Command group type names. - */ - -static char *command_group_type_names[] = { - #define G(_, STR) STR, - GROUPS - #undef G -}; - -/* - * Command help struct. - */ - -struct command_help { - char *name; - char *params; - char *summary; - command_group_type_t group; - char *since; -} command_help[] = { - __COMMANDS__ -}; - -/* - * Output command help to stdout. - */ - -static void -output_command_help(struct command_help *help) { - printf("\n \x1b[1m%s\x1b[0m \x1b[90m%s\x1b[0m\n", help->name, help->params); - printf(" \x1b[33msummary:\x1b[0m %s\n", help->summary); - printf(" \x1b[33msince:\x1b[0m %s\n", help->since); - printf(" \x1b[33mgroup:\x1b[0m %s\n", command_group_type_names[help->group]); -} - -/* - * Return command group type by name string. - */ - -static command_group_type_t -command_group_type_by_name(const char *name) { - for (int i = 0; i < COMMAND_GROUP_LENGTH; ++i) { - const char *group = command_group_type_names[i]; - if (0 == strcasecmp(name, group)) return i; - } - return 0; -} - -/* - * Output group names. - */ - -static void -output_group_help() { - for (int i = 0; i < COMMAND_GROUP_LENGTH; ++i) { - if (COMMAND_GROUP_UNKNOWN == i) continue; - const char *group = command_group_type_names[i]; - printf(" \x1b[90m-\x1b[0m %s\n", group); - } -} - -/* - * Output all command help, filtering by group or command name. - */ - -static void -output_help(int argc, const char **argv) { - int len = sizeof(command_help) / sizeof(struct command_help); - - if (argc && 0 == strcasecmp("groups", argv[0])) { - output_group_help(); - return; - } - - command_group_type_t group = argc - ? command_group_type_by_name(argv[0]) - : COMMAND_GROUP_UNKNOWN; - - for (int i = 0; i < len; ++i) { - struct command_help help = command_help[i]; - if (argc && !group && 0 != strcasecmp(help.name, argv[0])) continue; - if (group && group != help.group) continue; - output_command_help(&help); - } - puts(""); -} \ No newline at end of file From ff4058183bc6dfdc130a7172105bb0a02f76b4ec Mon Sep 17 00:00:00 2001 From: Pieter Noordhuis Date: Mon, 29 Nov 2010 19:27:06 +0100 Subject: [PATCH 4/8] Update linenoise --- deps/linenoise/example.c | 9 ++++ deps/linenoise/linenoise.c | 91 ++++++++++++++++++++++++++++++++++++++ deps/linenoise/linenoise.h | 9 ++++ 3 files changed, 109 insertions(+) diff --git a/deps/linenoise/example.c b/deps/linenoise/example.c index b3f9e9e35..ea0b515c1 100644 --- a/deps/linenoise/example.c +++ b/deps/linenoise/example.c @@ -2,9 +2,18 @@ #include #include "linenoise.h" + +void completion(const char *buf, linenoiseCompletions *lc) { + if (buf[0] == 'h') { + linenoiseAddCompletion(lc,"hello"); + linenoiseAddCompletion(lc,"hello there"); + } +} + int main(void) { char *line; + linenoiseSetCompletionCallback(completion); linenoiseHistoryLoad("history.txt"); /* Load the history at startup */ while((line = linenoise("hello> ")) != NULL) { if (line[0] != '\0') { diff --git a/deps/linenoise/linenoise.c b/deps/linenoise/linenoise.c index 045862e78..0ebef2e91 100644 --- a/deps/linenoise/linenoise.c +++ b/deps/linenoise/linenoise.c @@ -79,10 +79,12 @@ #include #include #include +#include "linenoise.h" #define LINENOISE_DEFAULT_HISTORY_MAX_LEN 100 #define LINENOISE_MAX_LINE 4096 static char *unsupported_term[] = {"dumb","cons25",NULL}; +static linenoiseCompletionCallback *completionCallback = NULL; static struct termios orig_termios; /* in order to restore at exit */ static int rawmode = 0; /* for atexit() function to check if restore is needed*/ @@ -195,6 +197,70 @@ static void refreshLine(int fd, const char *prompt, char *buf, size_t len, size_ if (write(fd,seq,strlen(seq)) == -1) return; } +static void beep() { + fprintf(stderr, "\x7"); + fflush(stderr); +} + +static void freeCompletions(linenoiseCompletions *lc) { + size_t i; + for (i = 0; i < lc->len; i++) + free(lc->cvec[i]); + if (lc->cvec != NULL) + free(lc->cvec); +} + +static int completeLine(int fd, const char *prompt, char *buf, size_t buflen, size_t *len, size_t *pos, size_t cols) { + linenoiseCompletions lc = { 0, NULL }; + int nread, nwritten; + char c = 0; + + completionCallback(buf,&lc); + if (lc.len == 0) { + beep(); + } else { + size_t stop = 0, i = 0; + size_t clen; + + while(!stop) { + /* Show completion or original buffer */ + if (i < lc.len) { + clen = strlen(lc.cvec[i]); + refreshLine(fd,prompt,lc.cvec[i],clen,clen,cols); + } else { + refreshLine(fd,prompt,buf,*len,*pos,cols); + } + + nread = read(fd,&c,1); + if (nread <= 0) { + freeCompletions(&lc); + return -1; + } + + switch(c) { + case 9: /* tab */ + i = (i+1) % (lc.len+1); + if (i == lc.len) beep(); + break; + case 27: /* escape */ + stop = 1; + break; + default: + /* update buffer and return */ + if (i < lc.len) { + nwritten = snprintf(buf,buflen,"%s",lc.cvec[i]); + *len = *pos = nwritten; + } + stop = 1; + break; + } + } + } + + freeCompletions(&lc); + return c; /* Return last read character */ +} + static int linenoisePrompt(int fd, char *buf, size_t buflen, const char *prompt) { size_t plen = strlen(prompt); size_t pos = 0; @@ -217,6 +283,18 @@ static int linenoisePrompt(int fd, char *buf, size_t buflen, const char *prompt) nread = read(fd,&c,1); if (nread <= 0) return len; + + /* Only autocomplete when the callback is set. It returns < 0 when + * there was an error reading from fd. Otherwise it will return the + * character that should be handled next. */ + if (c == 9 && completionCallback != NULL) { + c = completeLine(fd,prompt,buf,buflen,&len,&pos,cols); + /* Return on errors */ + if (c < 0) return len; + /* Read next character when 0 */ + if (c == 0) continue; + } + switch(c) { case 13: /* enter */ case 4: /* ctrl-d */ @@ -402,6 +480,19 @@ char *linenoise(const char *prompt) { } } +/* Register a callback function to be called for tab-completion. */ +void linenoiseSetCompletionCallback(linenoiseCompletionCallback *fn) { + completionCallback = fn; +} + +void linenoiseAddCompletion(linenoiseCompletions *lc, char *str) { + size_t len = strlen(str); + char *copy = malloc(len+1); + memcpy(copy,str,len+1); + lc->cvec = realloc(lc->cvec,sizeof(char*)*(lc->len+1)); + lc->cvec[lc->len++] = copy; +} + /* Using a circular buffer is smarter, but a bit more complex to handle. */ int linenoiseHistoryAdd(const char *line) { char *linecopy; diff --git a/deps/linenoise/linenoise.h b/deps/linenoise/linenoise.h index 0d76aea9c..c44bc3ade 100644 --- a/deps/linenoise/linenoise.h +++ b/deps/linenoise/linenoise.h @@ -34,6 +34,15 @@ #ifndef __LINENOISE_H #define __LINENOISE_H +typedef struct linenoiseCompletions { + size_t len; + char **cvec; +} linenoiseCompletions; + +typedef void(linenoiseCompletionCallback)(const char *, linenoiseCompletions *); +void linenoiseSetCompletionCallback(linenoiseCompletionCallback *); +void linenoiseAddCompletion(linenoiseCompletions *, char *); + char *linenoise(const char *prompt); int linenoiseHistoryAdd(const char *line); int linenoiseHistorySetMaxLen(int len); From 41945ba6ae4e365b39730f56ec0489551f8b42df Mon Sep 17 00:00:00 2001 From: Pieter Noordhuis Date: Mon, 29 Nov 2010 19:27:36 +0100 Subject: [PATCH 5/8] Use linenoise completion API from redis-cli --- src/redis-cli.c | 159 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 116 insertions(+), 43 deletions(-) diff --git a/src/redis-cli.c b/src/redis-cli.c index 865f09313..dd67ff84a 100644 --- a/src/redis-cli.c +++ b/src/redis-cli.c @@ -39,6 +39,7 @@ #include #include #include +#include #include "hiredis.h" #include "sds.h" @@ -89,58 +90,128 @@ static long long mstime(void) { *--------------------------------------------------------------------------- */ /* Output command help to stdout. */ -static void outputCommandHelp(struct commandHelp *help) { - printf("\n \x1b[1m%s\x1b[0m \x1b[90m%s\x1b[0m\n", help->name, help->params); - printf(" \x1b[33msummary:\x1b[0m %s\n", help->summary); - printf(" \x1b[33msince:\x1b[0m %s\n", help->since); - printf(" \x1b[33mgroup:\x1b[0m %s\n", commandGroups[help->group]); +static void cliOutputCommandHelp(struct commandHelp *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 (group) { + printf(" \x1b[33mgroup:\x1b[0m %s\r\n", commandGroups[help->group]); + } } -/* Return command group type by name string. */ -static int commandGroupIndex(const char *name) { - int i, len = sizeof(commandGroups)/sizeof(char*); - for (i = 0; i < len; i++) - if (strcasecmp(name, commandGroups[i]) == 0) - return i; - return -1; -} - -/* 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]); +/* Print generic help. */ +static void cliOutputGenericHelp() { + printf( + "redis-cli %s\r\n" + "Type: \"help @\" to get a list of commands in \r\n" + " \"help \" for help on \r\n" + " \"help \" to get a list of possible help topics\r\n" + " \"quit\" to exit\r\n", + REDIS_VERSION + ); } /* Output all command help, filtering by group or command name. */ -static void outputHelp(int argc, char **argv) { - int i, len = sizeof(commandHelp) / sizeof(struct commandHelp); - int group; +static void cliOutputHelp(int argc, char **argv) { + int i, len; struct commandHelp *help; + int group = -1; - if (argc && strcasecmp("groups", argv[0]) == 0) { - outputGroupHelp(); + if (argc == 0) { + cliOutputGenericHelp(); return; - } - - group = argc ? commandGroupIndex(argv[0]) : -1; - for (i = 0; i < len; i++) { - help = &commandHelp[i]; - if (group == -1) { - if (argc) { - if (strcasecmp(help->name, argv[0]) == 0) { - outputCommandHelp(help); - } - } else { - outputCommandHelp(help); - } - } else { - if (group == help->group) { - outputCommandHelp(help); + } 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; } } } - 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; config.raw_output = !strcasecmp(command,"info"); - if (!strcasecmp(command,"help")) { - outputHelp(--argc, ++argv); + if (!strcasecmp(command,"help") || !strcasecmp(command,"?")) { + cliOutputHelp(--argc, ++argv); return REDIS_OK; } if (!strcasecmp(command,"shutdown")) config.shutdown = 1; @@ -450,6 +521,7 @@ static void repl() { sds *argv; config.interactive = 1; + linenoiseSetCompletionCallback(completionCallback); while((line = linenoise("redis> ")) != NULL) { if (line[0] != '\0') { argv = sdssplitargs(line,&argc); @@ -525,6 +597,7 @@ int main(int argc, char **argv) { config.historyfile = NULL; config.tty = isatty(fileno(stdout)) || (getenv("FAKETTY") != NULL); config.mb_sep = '\n'; + cliInitHelp(); if (getenv("HOME") != NULL) { config.historyfile = malloc(256); From b2cc45bfbc5e8e264ce6c26c7803d2d24d47d340 Mon Sep 17 00:00:00 2001 From: Pieter Noordhuis Date: Mon, 29 Nov 2010 20:26:03 +0100 Subject: [PATCH 6/8] Refactor and support help for command names with spaces --- src/redis-cli.c | 124 +++++++++++++++++++++++++++--------------------- 1 file changed, 69 insertions(+), 55 deletions(-) diff --git a/src/redis-cli.c b/src/redis-cli.c index dd67ff84a..e22ba3766 100644 --- a/src/redis-cli.c +++ b/src/redis-cli.c @@ -89,6 +89,50 @@ static long long mstime(void) { * Help functions *--------------------------------------------------------------------------- */ +#define CLI_HELP_COMMAND 1 +#define CLI_HELP_GROUP 2 + +typedef struct { + int type; + int argc; + sds *argv; + sds full; + + /* Only used for help on commands */ + struct commandHelp *org; +} helpEntry; + +static helpEntry *helpEntries; +static int helpEntriesLen; + +static void cliInitHelp() { + int commandslen = sizeof(commandHelp)/sizeof(struct commandHelp); + int groupslen = sizeof(commandGroups)/sizeof(char*); + int i, len, pos = 0; + helpEntry tmp; + + helpEntriesLen = len = commandslen+groupslen; + helpEntries = malloc(sizeof(helpEntry)*len); + + for (i = 0; i < groupslen; i++) { + tmp.argc = 1; + tmp.argv = malloc(sizeof(sds)); + tmp.argv[0] = sdscatprintf(sdsempty(),"@%s",commandGroups[i]); + tmp.full = tmp.argv[0]; + tmp.type = CLI_HELP_GROUP; + tmp.org = NULL; + helpEntries[pos++] = tmp; + } + + for (i = 0; i < commandslen; i++) { + tmp.argv = sdssplitargs(commandHelp[i].name,&tmp.argc); + tmp.full = sdsnew(commandHelp[i].name); + tmp.type = CLI_HELP_COMMAND; + tmp.org = &commandHelp[i]; + helpEntries[pos++] = tmp; + } +} + /* Output command help to stdout. */ static void cliOutputCommandHelp(struct commandHelp *help, int group) { printf("\r\n \x1b[1m%s\x1b[0m \x1b[90m%s\x1b[0m\r\n", help->name, help->params); @@ -113,9 +157,10 @@ static void cliOutputGenericHelp() { /* Output all command help, filtering by group or command name. */ static void cliOutputHelp(int argc, char **argv) { - int i, len; - struct commandHelp *help; + int i, j, len; int group = -1; + helpEntry *entry; + struct commandHelp *help; if (argc == 0) { cliOutputGenericHelp(); @@ -130,13 +175,21 @@ static void cliOutputHelp(int argc, char **argv) { } } - len = sizeof(commandHelp)/sizeof(struct commandHelp); assert(argc > 0); - for (i = 0; i < len; i++) { - help = &commandHelp[i]; + for (i = 0; i < helpEntriesLen; i++) { + entry = &helpEntries[i]; + if (entry->type != CLI_HELP_COMMAND) continue; + + help = entry->org; if (group == -1) { - if (strcasecmp(help->name, argv[0]) == 0) { - cliOutputCommandHelp(help,1); + /* Compare all arguments */ + if (argc == entry->argc) { + for (j = 0; j < argc; j++) { + if (strcasecmp(argv[j],entry->argv[j]) != 0) break; + } + if (j == argc) { + cliOutputCommandHelp(help,1); + } } } else { if (group == help->group) { @@ -147,69 +200,30 @@ static void cliOutputHelp(int argc, char **argv) { 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; + sds tmp; if (strncasecmp(buf,"help ",5) == 0) { startpos = 5; while (isspace(buf[startpos])) startpos++; - mask = CLI_COMPLETE_COMMAND | CLI_COMPLETE_GROUP; + mask = CLI_HELP_COMMAND | CLI_HELP_GROUP; } else { - mask = CLI_COMPLETE_COMMAND; + mask = CLI_HELP_COMMAND; } - for (i = 0; i < completionEntriesLen; i++) { - if (!(completionEntries[i].type & mask)) continue; + for (i = 0; i < helpEntriesLen; i++) { + if (!(helpEntries[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); + if (strncasecmp(buf+startpos,helpEntries[i].full,matchlen) == 0) { + tmp = sdsnewlen(buf,startpos); + tmp = sdscat(tmp,helpEntries[i].full); linenoiseAddCompletion(lc,tmp); - free(tmp); + sdsfree(tmp); } } } From c54afb6d0d9808e38248e55a3220868735aaab44 Mon Sep 17 00:00:00 2001 From: Pieter Noordhuis Date: Mon, 29 Nov 2010 20:53:57 +0100 Subject: [PATCH 7/8] Minor update to linenoise --- deps/linenoise/linenoise.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/deps/linenoise/linenoise.c b/deps/linenoise/linenoise.c index 0ebef2e91..b6f4d4f9b 100644 --- a/deps/linenoise/linenoise.c +++ b/deps/linenoise/linenoise.c @@ -243,10 +243,14 @@ static int completeLine(int fd, const char *prompt, char *buf, size_t buflen, si if (i == lc.len) beep(); break; case 27: /* escape */ + /* Re-show original buffer */ + if (i < lc.len) { + refreshLine(fd,prompt,buf,*len,*pos,cols); + } stop = 1; break; default: - /* update buffer and return */ + /* Update buffer and return */ if (i < lc.len) { nwritten = snprintf(buf,buflen,"%s",lc.cvec[i]); *len = *pos = nwritten; From bbac56c2f823a6ab2170e1b00b93a620188b76da Mon Sep 17 00:00:00 2001 From: antirez Date: Wed, 1 Dec 2010 11:18:59 +0100 Subject: [PATCH 8/8] added support for ctrl-l and clear command into redis-cli. To clear the screen is a good idea from time to time :). Also linenoise updated to the current version to support this new feature. --- deps/linenoise/linenoise.c | 20 ++++++++++++++++++++ deps/linenoise/linenoise.h | 3 +++ src/redis-cli.c | 2 ++ 3 files changed, 25 insertions(+) diff --git a/deps/linenoise/linenoise.c b/deps/linenoise/linenoise.c index b6f4d4f9b..dd4341366 100644 --- a/deps/linenoise/linenoise.c +++ b/deps/linenoise/linenoise.c @@ -9,6 +9,8 @@ * the 2010 UNIX computers around. * * Copyright (c) 2010, Salvatore Sanfilippo + * Copyright (c) 2010, Pieter Noordhuis + * * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -66,6 +68,17 @@ * CUF (CUrsor Forward) * Sequence: ESC [ n C * Effect: moves cursor forward of n chars + * + * The following are used to clear the screen: ESC [ H ESC [ 2 J + * This is actually composed of two sequences: + * + * cursorhome + * Sequence: ESC [ H + * Effect: moves the cursor to upper left corner + * + * ED2 (Clear entire screen) + * Sequence: ESC [ 2 J + * Effect: clear the whole screen * */ @@ -265,6 +278,10 @@ static int completeLine(int fd, const char *prompt, char *buf, size_t buflen, si return c; /* Return last read character */ } +void linenoiseClearScreen(void) { + write(STDIN_FILENO,"\x1b[H\x1b[2J",7); +} + static int linenoisePrompt(int fd, char *buf, size_t buflen, const char *prompt) { size_t plen = strlen(prompt); size_t pos = 0; @@ -432,6 +449,9 @@ up_down_arrow: pos = len; refreshLine(fd,prompt,buf,len,pos,cols); break; + case 12: /* ctrl+l, clear screen */ + linenoiseClearScreen(); + refreshLine(fd,prompt,buf,len,pos,cols); } } return len; diff --git a/deps/linenoise/linenoise.h b/deps/linenoise/linenoise.h index c44bc3ade..76a703c28 100644 --- a/deps/linenoise/linenoise.h +++ b/deps/linenoise/linenoise.h @@ -4,6 +4,8 @@ * See linenoise.c for more information. * * Copyright (c) 2010, Salvatore Sanfilippo + * Copyright (c) 2010, Pieter Noordhuis + * * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -48,5 +50,6 @@ int linenoiseHistoryAdd(const char *line); int linenoiseHistorySetMaxLen(int len); int linenoiseHistorySave(char *filename); int linenoiseHistoryLoad(char *filename); +void linenoiseClearScreen(void); #endif /* __LINENOISE_H */ diff --git a/src/redis-cli.c b/src/redis-cli.c index a39874722..2aedcc4a2 100644 --- a/src/redis-cli.c +++ b/src/redis-cli.c @@ -561,6 +561,8 @@ static void repl() { config.hostip = sdsnew(argv[1]); config.hostport = atoi(argv[2]); cliConnect(1); + } else if (argc == 1 && !strcasecmp(argv[0],"clear")) { + linenoiseClearScreen(); } else { long long start_time = mstime(), elapsed;