在学习redis的client源码的过程中,遇到了linenoise这个函数,知道它是一个处理命令的工具,但它具体能做什么工作,怎样作这些工作还是不清楚。通过查看相关资料,对linenoise的功能及部分使用方法有了初步的认识,下面就让我介绍一下:
1,linenoise是个处理指令的交互窗口
在redis中,linenoise用在client中,就像是一个交互窗口,在这个窗口中,可以输入指令,可以显示返回结果。除非Ctrl+C退出,一般程序会一直停留在这个窗口上。实现这一点,其实并不难,通过while调用函数就可以实现。看一下代码就清楚了,下面是linenoise的API接口。
char *linenoise(const char *prompt);
函数的输入值为提示符(更像linux的虚拟终端了,哈哈),函数的返回值为输入的字符串。
redis-cli通过如下方式调用linenoise,
while((line = linenoise(context ? config.prompt : "not connected> ")) != NULL) {
可以看出promt为config.promt配置的一个字符串,或者"not connected> "。
而只要输入不为空,就可以保证输入的line可以被while内的代码处理。下图为redis-cli连接server后的界面,更直观。
2,linenoise可以实现长字符串自动换行
在没有换行处理的情况下,不按回车键,字母就会一直往后填,就像text文本一样,很不容易阅读。而linenoise解决了这个问题,当字符个数超过终端串口的长度时,会自动换行,可以通过如下代码设置。
linenoiseSetMultiLine(1)
3,支持历史回溯功能
啥意思呢,就是更像linux虚拟终端了,它可以记录之前输入的命令,并可以通过UP、DOWN上下查找。也可以将之前的命令存储到文件之中。具体实现有以下四个函数。
int linenoiseHistoryAdd(const char *line);
int linenoiseHistorySetMaxLen(int len);
int linenoiseHistorySave(const char *filename);
int linenoiseHistoryLoad(const char *filename);
4,命令行自动补全功能
可以通过Tab键补全命令行,根据几个字母补全,补全的字母为何是需要自己定义的。主要函数包括两个:
/* Register a callback function to be called for tab-completion. */
void linenoiseSetCompletionCallback(linenoiseCompletionCallback *fn) {
completionCallback = fn;
}
void completion(const char *buf, linenoiseCompletions *lc)
其中,第一个函数为接口函数,将函数指针completionCallback指向completion。
第二个函数为实现函数,在redis中没有定义completion,直接定义了completionCallback。如下:
/* Linenoise completion callback. */
static void completionCallback(const char *buf, linenoiseCompletions *lc) {
size_t startpos = 0;
int mask;
int i;
size_t matchlen;
sds tmp;
//判断mask类型,是CLI_HELP_COMMAND,CLI_HELP_GROUP
if (strncasecmp(buf,"help ",5) == 0) {
startpos = 5;
while (isspace(buf[startpos])) startpos++;
mask = CLI_HELP_COMMAND | CLI_HELP_GROUP;
} else {
mask = CLI_HELP_COMMAND;
}
//根据已输入的字符串及其长度判断,遍历helpEntries,查看其中是否有与输入字符串匹配的值
for (i = 0; i < helpEntriesLen; i++) {
if (!(helpEntries[i].type & mask)) continue;
matchlen = strlen(buf+startpos);
if (strncasecmp(buf+startpos,helpEntries[i].full,matchlen) == 0) {
tmp = sdsnewlen(buf,startpos);
tmp = sdscat(tmp,helpEntries[i].full);
linenoiseAddCompletion(lc,tmp);
sdsfree(tmp);
}
}
}
该函数可以根据已输入的字符串,查找helpEntries数组中与其匹配的字符串,找到后,填入到linenoiseAddCompletion(lc,tmp)中,进行补全。
5,语法提示功能
也是使用回调函数,在helpEntries中查找匹配的字符串,方法与命令补全类似。函数声明如下:
linenoiseSetHintsCallback(hints);
char *hints(const char *buf, int *color, int *bold);
前者为接口,后者为实现。
总结:
关于linenoise的功能及其使用方法具体就这5个,而这些功能如何实现还待进一步探究。