一个小巧但功能强大的跨平台命令行工具库Crossline

Crossline

Crossline是一个很小的跨平台命令行工具库,类似Linux上的readline。

项目地址:https://github.com/JunchuanWang80/Crossline

因为开发一个项目需要支持跨平台命令行,在Linux上readline是首选,但是Windows上没法直接用。后来搜到了一个开源项目linenoise,这个命令行工具库是Redis的作者开发的,Redis,Andriod和MongoDB都使用了。这个工具库很小,只有1100行左右代码(readline超过3万行代码,并且还依赖ncurses库),但是它只能在Linux上运行,支持的快捷键也很少,功能也少。后来搜到了linenoise-ng,这个项目是ArangoDB开源的,最初是从MongoDB版本的linenoise移植出来的。这个开源项目非常强大,支持Windows/Linux,支持很多快捷键和功能,并且支持Unicode。起初打算用这个库,后来发现这个库依然挺大的,代码大约有4,300行并且挺复杂的,还混合使用了C++和C,还有不少动态内存操作(linenoise也有)。我觉得一个跨平台命令行工具库可以实现的更简单,于是做了原型验证,然后使用了不同的方式实现了这个全新的很小但是功能很多的夸平台命令行工具库。

功能和特色

支持Windows,Linux,vt100和xterm。

支持79个快捷键和37个功能。

支持大部分readline快捷键(Emacs标准绑定): 移动,修改,剪切粘贴,自动补齐,历史命令行,控制。

支持部分Windows命令行快捷键,增加一些新的方便使用的快捷键。

支持历史命令行浏览,显示,清空,保存到文件以及从文件加载。

支持自动补齐,关键字及帮助显示和语法提示。

支持强大的交互式历史命令行搜索,支持匹配多个包含和排除规则,匹配不区分大小写。

在命令行搜素模式下支持除了自动补齐和历史命令行外的所有快捷键。

支持自动分页功能,用于自动补齐显示,历史命令行显示和搜索显示,帮助信息显示,会根据窗口大小自动调整。

支持方便的内置F1帮助功能,可以在编辑模式和命令行搜索模式下使用,可以随时使用不影响当前已输入命令行。

支持方便的Ctrl-^键盘调试功能,可以看到按下的键产生的字符序列。

支持Ctrl-C退出编辑,Linux下支持Ctrl-Z挂起并恢复编辑,这2个快捷键在编辑模式和命令行搜索模式下都适用。

支持管道作为输入。

纯C代码,没有第三方库依赖。

没有动态内存操作: malloc/free/realloc/new/delete/strdup/etc。

非常小,只有1000行左右代码,逻辑简单容易阅读。

可以很容易的扩展支持新的快捷键和功能。

以后会支持Unicode。

快捷键列表

其他命令

F1          显示快捷键帮助

Ctrl-^      进入键盘调试模式

移动命令

Ctrl-B,Left    左移一个字符

Ctrl-F,Right  右移一个字符

Alt-B,ESC+Left,Ctrl-Left,Alt-Left         左移一个单词(Ctrl-Left,Alt-Left只支持Windows/Xterm)

Alt-F,ESC+Right,Ctrl-Right,Alt-Right  右移一个单词(Ctrl-Right,Alt-Right只支持Windows/Xterm)

Ctrl-A,Home  移到行首

Ctrl-E,End     移到行尾

Ctrl-L                清屏并显示当前行

编辑命令

Ctrl-H,Backspace  删除光标前字符

Ctrl-D,DEL            删除光标处字符

Alt-U, ESC+Up,Ctrl-Up,Alt-Up  将当前单词改成全大写(Ctrl-Up,Alt-Up只支持Windows/Xterm)

Alt-L,ESC+Down,Ctrl-Down,Alt-Down  将当前单词改成全小写(Ctrl-Down,Alt-Down只支持Windows/Xterm)

Alt-C    将当前单词改成首字母大写

Alt-\      删除光标左右侧空格

Ctrl-T    交换光标处2个字符

剪切粘贴

Ctrl-K,ESC+End,Ctrl-End,Alt-End    从光标处剪切到行尾(Ctrl-End,Alt-End只支持Windows/Xterm)

Ctrl-U,ESC+Home,Ctrl-Home,Alt-Home    从光标处剪切到行首(Ctrl-Home,Alt-Home只支持Windows/Xterm)

Ctrl-X    剪切整行

Alt-Backspace,Esc+Backspace,Clt-Backspace    剪切光标前面的单词(Clt-Backspace only supports Windows/Xterm)

Alt-D,ESC+Del,Alt-Del,Ctrl-Del    剪切光标后面的单词(Alt-Del,Ctrl-Del只支持Windows/Xterm)

Ctrl-W    从光标处向左剪切到空格止

Ctrl-Y,Ctrl-V,Insert    粘贴剪切文本

自动补齐命令

TAB,Ctrl-I    自动补齐

Alt-=,Alt-?    列出补齐项

历史命令

Ctrl-P,Up        取上一个历史命令行

Ctrl-N,Down    取下一个历史命令行

Alt-<, PgUp     取第一个历史命令行

Alt->, PgDn     取最后一个历史命令行(当前输入)

Ctrl-R,Ctrl-S    进入命令行搜索模式

F4                     用当前输入进入命令行搜索模式

F1                     在命令行搜索模式下显示搜索匹配语法

F2                     显示历史命令行

F3                     清空历史命令行(需要确认)

控制命令

Enter, Ctrl-J,Ctrl-M    返回当前命令行

Ctrl-C,Ctrl-G    丢弃当前命令行并返回

Ctrl-D                 如果当前命令行为空则返回

Alt-R                  清空当前命令行

Ctrl-Z                 挂起命令行(Linux适用,fg可以继续编辑)

历史命令行搜索功能

原始的readline支持增量搜索(Ctrl-R,Ctrl-S)和非增量搜索(Alt-N,Alt-P)。这2种方式都不方便,效率也不高,所以实现了全新的交互式命令行搜索功能。

匹配语法

使用空格分开多个匹配项,每个匹配项都不区分大小写(小技巧:可以使用Insert插入上次搜索关键字继续编辑)

select: 选择包含select的命令行

-select: 选择不包含select的命令行

"select from": 选择包含select from的命令行

-"select from": 选择不包含select from的命令行

"select from" where -"order by" -limit: 选择包含select from以及where,但不包含order by或者limit的命令行

例子

SQL> <F2> // show history

  1 hello world

  2 select from user

  3 from select table

  4 SELECT from student

  5 Select from teacher

SQL> <Ctrl+R>

Input Patterns <F1> help: select from

  1 select from user

  2 from select table

  3 SELECT from student

  4 Select from teacher

Input history id: 3

SQL> SELECT from student<Alt+R> // Revert line

SQL> <F4>

Input Patterns <F1> help: <Insert> // paste last history pattern: select from

Input Patterns <F1> help: "select from"

  1 select from user

  2 SELECT from student

  3 Select from teacher

Input history id: 3

SQL> Select from teacher<Alt+R>

SQL> SELECT from<F4> // search with pattern: Select from

Input Patterns <F1> help: SELECT from

Input Patterns <F1> help: "SELECT from" -user -teacher

  1 SELECT from student

Input history id: 1

SQL> SELECT from student

Crossline APIs

// Main API to read a line,return buf if get line,return NULL if EOF。

char* crossline_readline (char *buf,int size,const char *prompt);

// Set move/cut word delimiter,default is all not digital and alphabetic characters

void crossline_delimiter_set (const char *delim);

// History APIs

int crossline_history_save (const char *filename);

int crossline_history_load (const char *filename);

void crossline_history_show (void);

void crossline_history_clear (void);

/* Completion APIs */

// Register completion callback

void crossline_completion_register (crossline_completion_callback pCbFunc);

// Add completion in callback。 Word is must,help for word is optional。

void crossline_completion_add (crossline_completions_t *pCompletions,const char *word,const char *help);

// Set syntax hints in callback

void crossline_hints_set (crossline_completions_t *pCompletions,const char *hints);

简单例子

代码在example.c

static void completion_hook (char const *buf,crossline_completions_t *pCompletion)

{

    int i;

    static const char *cmd[] = {"insert","select","update","delete","create","drop","show","describe","help","exit","history",NULL};

    for (i = 0; NULL != cmd[i]; ++i) {

        if (0 == strncmp(buf,cmd[i],strlen(buf))) {

            crossline_completion_add (pCompletion,cmd[i],NULL);

        }

    }

}

int main ()

{

    char buf[256];

    crossline_completion_register (completion_hook);

    crossline_history_load ("history。txt");

    while (NULL != crossline_readline (buf,sizeof(buf),"Crossline> ")) {

        printf ("Read line: \"%s\"\n",buf);

    }   

    crossline_history_save ("history。txt");

    return 0;

}

SQL解析器例子

代码在example_sql.c,这个例子实现了一个简单的SQL语法分析器,可以解析如下语法,代码较多这里就不放了。

insert into <table> set column1=value1,column2=value2,。。。

select <* | column1,columnm2,。。。> from <table> [where] [order by] [limit] [offset]

update <table> set column1=value1,column2=value2 [where] [order by] [limit] [offset]

delete from <table> [where] [order by] [limit] [offset]

create [unique] index <name> on <table> (column1,column2,。。。)

drop {table | index} <name>

show {tables | databases}

describe <table>

help {insert | select | update | delete | create | drop | show | describe | help | exit | history}

可以用这个例子来测试上面的快捷键

SQL> <TAB> // show autocomplete words and help

insert    Insert a record to table

select    Select records from table

update    Update records in table

delete    Delete records from table

create    Create index on table

drop      Drop index or table

show      Show tables or databases

describe  Show table schema

help      Show help for topic

exit      Exit shell

history    Show history

*** Press <Space> or <Enter> to continue . . .

SQL> help <TAB> // show autocomplete words list

insert select update delete create drop show

describe help exit history

SQL> create index <TAB> // show autocomplete hints

Please input: index name

编译与测试

Windows MSVC

cl -D_CRT_SECURE_NO_WARNINGS -W4 User32.Lib crossline.c example.c /Feexample.exe

cl -D_CRT_SECURE_NO_WARNINGS -W4 User32.Lib crossline.c example_sql.c /Feexample_sql.exe

Windows Clang

clang -D_CRT_SECURE_NO_WARNINGS -Wall -lUser32 crossline.c example.c -o example.exe

clang -D_CRT_SECURE_NO_WARNINGS -Wall -lUser32 crossline.c example_sql.c -o example_sql.exe

Linux Clang

clang -Wall crossline.c example.c -o example

clang -Wall crossline.c example_sql.c -o example_sql

GCC(Linux, MinGW, Cygwin, MSYS2)

gcc -Wall crossline.c example.c -o example

gcc -Wall crossline.c example_sql.c -o example_sql

其它

这里只列出了部分内容,详细信息请参考项目的README.md

项目地址:https://github.com/JunchuanWang80/Crossline

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,635评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,628评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,971评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,986评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,006评论 6 394
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,784评论 1 307
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,475评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,364评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,860评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,008评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,152评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,829评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,490评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,035评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,156评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,428评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,127评论 2 356

推荐阅读更多精彩内容