【解锁】Linenoise——C命令行处理工具

Linenoise

今天解锁一个开源的REPL工具——Linenoise。Linenoise是可以完全代替readline的,非常轻量级的命令行处理工具。Redis,MongoDB和Android都将Linenoise作为命令行解析工具,那么今天我们就来解锁这个开源的命令行处理工具,也许某一天在你的项目里会派上用场。

特性

  • 支持单行和多行编辑模式,实现了常用的键绑定。
  • 支持历史命令记录
  • 支持命令不全
  • 支持命令提示
  • 超轻量级,大约1100行代码(readline大约30,000行代码)
  • 非常方便的融入你的项目李(一个.h,一个.c)

api简介

Linenoise非常易于使用,阅读该库附带的示例将使您尽快熟悉。以下是API调用及其使用方式。
char *linenoise(const char *prompt);

该接口现实命令提示符如hello> ,并返回用户输入缓冲区,当内存不足活文件结尾是返回NULL。
使用该接口循环接受用户输入命令并现实提示符

while((line = linenoise("hello> ")) != NULL) {
    printf("You wrote: %s\n", line);
    linenoiseFree(line); /* Or just free(line) if you use libc malloc. */
}

x.gif

单行 or 多行编辑

默认情况下linenoise使用单行编辑,如果需要输入大量内容可以开启多行编辑模式。

linenoiseSetMultiLine(1);

命令历史

Linenoise支持历史记录,因此用户不必一次又一次地键入相同的内容,而是可以使用向下和向上箭头来搜索和重新编辑已经插入的命令。——个人觉得这个功能非常有用。

// 将一条你执行的命令添加到历史,从而你可以通过上下键找到它
int linenoiseHistoryAdd(const char *line);
// 要使用历史记录,您必须设置历史记录的长度(默认情况下为零,因此,如果未设置正确的长度,则将禁用历史记录)
int linenoiseHistorySetMaxLen(int len);
// Linenoise直接支持将历史记录保存到历史记录文件中,通过下面两个接口可以存取历史文件内容
int linenoiseHistorySave(const char *filename);
int linenoiseHistoryLoad(const char *filename);

下面是一段范例代码

    while((line = linenoise("hello> ")) != NULL) {
        /* Do something with the string. */
        if (line[0] != '\0' && line[0] != '/') {
            printf("echo: '%s'\n", line);
            linenoiseHistoryAdd(line); /* Add to the history. */
            linenoiseHistorySave("history.txt"); /* Save the history on disk. */
        } else if (!strncmp(line,"/historylen",11)) {
            /* The "/historylen" command will change the history len. */
            int len = atoi(line+11);
            linenoiseHistorySetMaxLen(len);
        } else if (line[0] == '/') {
            printf("Unreconized command: %s\n", line);
        }
        free(line);
    }

自动补全

Linenoise支持自动补全功能,即用户按下<TAB>键时会自动补全你的命令。
为了实现这一功能,你可以注册并实现你的补全函数。

// 注册自动补全函数completion
linenoiseSetCompletionCallback(completion);

注册的补全必须是一个void返回值函数,需要传入一个const char指针(该指针是用户到目前为止已键入的命令字符)和一个linenoiseCompletions对象指针,该对象指针用作是linenoiseAddCompletion将回调添加到补全中的参数。一个例子将使其更加清楚:

void completion(const char *buf, linenoiseCompletions *lc) {
    if (buf[0] == 'h') {
        linenoiseAddCompletion(lc,"hello");
        linenoiseAddCompletion(lc,"hello there");
    }
}

用户输入'h'是会现实补全列表"hello","hello there"。
x.gif

命令提示

Linenoise具有称为提示的功能,当你使用Linenoise实现REPL时,这个功能非常有用。
当用户键入时,该功能会在光标的右侧显示可能有用的提示。提示可以使用与用户键入的颜色不同的颜色显示,也可以加粗。
例如,当用户开始输入"git remote add"提示时,可以在提示的右侧显示字符串<name> <url>
改接口与自动补全功能类似:

linenoiseSetHintsCallback(hints);

回调函数实现如下:

char *hints(const char *buf, int *color, int *bold) {
    if (!strcasecmp(buf,"git remote add")) {
        *color = 35;
        *bold = 0;
        return " <name> <url>";
    }
    return NULL;
}

x.gif
颜色编码:

red = 31
green = 32
yellow = 33
blue = 34
magenta = 35
cyan = 36
white = 37;

清屏

有时候你可能想通过输入某条命令来清屏,比如hello> clear,那么可以使用下面的接口:

void linenoiseClearScreen(void);

总结

今天主要解锁了Linenoise的用法,Linenoise非常简单,且很容易嵌入到你的项目里。希望对有REPL需求的小伙伴有些帮助。后续将继续解锁Linenoise的进化版Linenoise-NG(Linenoise Next Generation)。尽请期待~

【解锁】 Linenoise-NG(Linenoise Next Generation)——C++命令行处理工具已更新。

Linenoise代码托管地址

43 声望
2 粉丝
0 条评论
推荐阅读
【运维经】第8章——go get 加速
近几期一直在讲加速,今天该轮到golang了,因为 Go 1.13 将 GOPROXY 默认成了中国大陆无法访问的 [链接] ,所以我们国内的开发者以后必须先修改 GOPROXY 才能正常使用 go 来开发应用了。好在七牛提供了国内代理。

夏洛克阅读 2.3k

Redis 发布订阅模式:原理拆解并实现一个消息队列
“65 哥,如果你交了个漂亮小姐姐做女朋友,你会通过什么方式将这个消息广而告之给你的微信好友?““那不得拍点女朋友的美照 + 亲密照弄一个九宫格图文消息在朋友圈发布大肆宣传,暴击单身狗。”像这种 65 哥通过朋...

码哥字节6阅读 1.3k

封面图
C 程序眼中的 Unicode
去年写了一篇文章「在 C 程序中处理 UTF-8 字符串」,介绍了如何使用 GLib 提供的 UTF-8 字符串处理函数来实现基本的 UTF-8 文本处理。不过,GLib 是一个功能比较全面的 C 程序库,C 字符串处理仅仅是它的一个很...

garfileo3阅读 5.6k评论 5

Redis高可用之哨兵机制实现细节
在上一篇的文章《Redis高可用全景一览》中,我们学习了 Redis 的高可用性。高可用性有两方面含义:一是服务少中断,二是数据少丢失。主从库模式和哨兵保证了服务少中断,AOF 日志和 RDB 快照保证了数据少丢失。

杨同学technotes4阅读 1.1k

计算机如何表示整数
在计算机中,任何的数据都是用二进制: 0 和 1 来表示。整数也不例外。生活中的 10,在 8 个字节的整数中表示为 00001010。但是这样子只能表示正数和零。怎么表示负数呢?于是有了符号位的概念。在 8 个字节的整...

kang2阅读 3k评论 7

麒麟操作系统 (kylinos) 从入门到精通 - 研发环境 - 第二十一篇 C++/C语言开发环境搭建
类别:笔记本型号:中国长城 NF14C硬件平台:飞腾处理器(ArmV8 指令集)系统:银河麒麟操作系统 V10 SP1(2203) 关键词:信创,麒麟系统,linux,c++,c,内核飞腾,arm

码上世界1阅读 2.3k评论 1

封面图
1.5万字总结 Redis 常见面试题&知识点
Redis 是一个基于 C 语言开发的开源数据库(BSD 许可),与传统数据库不同的是 Redis 的数据是存在内存中的(内存数据库),读写速度非常快,被广泛应用于缓存方向。并且,Redis 存储的是 KV 键值对数据。

JavaGuide3阅读 804

封面图
43 声望
2 粉丝
宣传栏