为什么 rl_bind_key 的自定义函数在 OSX/macOS 的 readline 中失败
Why does rl_bind_key with custom function fail in readline on OSX/macOS
我构建了一个 shell 试图让制表符 (\t
) 键使用 rl_bind_key()
做一些自定义的事情,但它在 macOS Sierra 中不起作用,但它有效在 Ubuntu、Fedora 和 CentOS 上。这是 mcve:
#include <stdlib.h>
#include <stdio.h>
#include <readline/readline.h>
static int cmd_complete(int count, int key)
{
printf("\nCustom tab action goes here...\n");
rl_forced_update_display();
return 0;
}
char *interactive_input()
{
char *buffer = readline(" > ");
return buffer;
}
int main(int argc, char **argv)
{
rl_bind_key('\t', cmd_complete); // this doesn't seem to work in macOS
char *buffer = 0;
while (!buffer || strncmp(buffer, "exit", 4)) {
if (buffer) { free(buffer); buffer=0; }
// get command
buffer = interactive_input();
printf("awesome command: %s\n", buffer);
}
free(buffer);
return 0;
}
我像这样使用 Clang 编译:
$ cc -lreadline cli.c -o cli
此行为的原因是什么,我该如何解决?
我正在使用标志 -lreadline
,但我并不知道,Clang 似乎秘密地使用了 libedit(我也看到它叫做 editline)。在 libedit 中,出于某种原因(这值得另一个问题),rl_bind_key
似乎不适用于除 rl_insert
.
之外的任何东西
所以我找到的一个解决方案是使用 Homebrew 安装 GNU Readline (brew install readline
),然后为了确保我使用那个版本,我这样编译:
$ cc -lreadline cli.c -o cli -L/usr/local/opt/readline/lib -I/usr/local/opt/readline/include
事实上,当你安装 readline 时,它会在安装结束时告诉你这个,或者如果你这样做 brew info readline
:
gns-mac1:~ gns$ brew info readline
readline: stable 7.0.3 (bottled) [keg-only]
Library for command-line editing
https://tiswww.case.edu/php/chet/readline/rltop.html
/usr/local/Cellar/readline/7.0.3_1 (46 files, 1.5MB)
Poured from bottle on 2017-10-24 at 12:21:35
From: https://github.com/Homebrew/homebrew-core/blob/master/Formula/readline.rb
==> Caveats
This formula is keg-only, which means it was not symlinked into /usr/local,
because macOS provides the BSD libedit library, which shadows libreadline.
In order to prevent conflicts when programs look for libreadline we are
defaulting this GNU Readline installation to keg-only..
For compilers to find this software you may need to set:
LDFLAGS: -L/usr/local/opt/readline/lib
CPPFLAGS: -I/usr/local/opt/readline/include
libedit 来源 rl_bind_key
所以这就是它在 libedit 中不起作用的原因。我下载了源代码,rl_bind_key
函数是这样定义的:
/*
* bind key c to readline-type function func
*/
int
rl_bind_key(int c, rl_command_func_t *func)
{
int retval = -1;
if (h == NULL || e == NULL)
rl_initialize();
if (func == rl_insert) {
/* XXX notice there is no range checking of ``c'' */
e->el_map.key[c] = ED_INSERT;
retval = 0;
}
return retval;
}
所以它似乎被设计为不适用于 rl_insert
以外的任何东西。这似乎是一个错误,而不是一个功能。我希望我知道如何成为 libedit 的贡献者。
我构建了一个 shell 试图让制表符 (\t
) 键使用 rl_bind_key()
做一些自定义的事情,但它在 macOS Sierra 中不起作用,但它有效在 Ubuntu、Fedora 和 CentOS 上。这是 mcve:
#include <stdlib.h>
#include <stdio.h>
#include <readline/readline.h>
static int cmd_complete(int count, int key)
{
printf("\nCustom tab action goes here...\n");
rl_forced_update_display();
return 0;
}
char *interactive_input()
{
char *buffer = readline(" > ");
return buffer;
}
int main(int argc, char **argv)
{
rl_bind_key('\t', cmd_complete); // this doesn't seem to work in macOS
char *buffer = 0;
while (!buffer || strncmp(buffer, "exit", 4)) {
if (buffer) { free(buffer); buffer=0; }
// get command
buffer = interactive_input();
printf("awesome command: %s\n", buffer);
}
free(buffer);
return 0;
}
我像这样使用 Clang 编译:
$ cc -lreadline cli.c -o cli
此行为的原因是什么,我该如何解决?
我正在使用标志 -lreadline
,但我并不知道,Clang 似乎秘密地使用了 libedit(我也看到它叫做 editline)。在 libedit 中,出于某种原因(这值得另一个问题),rl_bind_key
似乎不适用于除 rl_insert
.
所以我找到的一个解决方案是使用 Homebrew 安装 GNU Readline (brew install readline
),然后为了确保我使用那个版本,我这样编译:
$ cc -lreadline cli.c -o cli -L/usr/local/opt/readline/lib -I/usr/local/opt/readline/include
事实上,当你安装 readline 时,它会在安装结束时告诉你这个,或者如果你这样做 brew info readline
:
gns-mac1:~ gns$ brew info readline
readline: stable 7.0.3 (bottled) [keg-only]
Library for command-line editing
https://tiswww.case.edu/php/chet/readline/rltop.html
/usr/local/Cellar/readline/7.0.3_1 (46 files, 1.5MB)
Poured from bottle on 2017-10-24 at 12:21:35
From: https://github.com/Homebrew/homebrew-core/blob/master/Formula/readline.rb
==> Caveats
This formula is keg-only, which means it was not symlinked into /usr/local,
because macOS provides the BSD libedit library, which shadows libreadline.
In order to prevent conflicts when programs look for libreadline we are
defaulting this GNU Readline installation to keg-only..
For compilers to find this software you may need to set:
LDFLAGS: -L/usr/local/opt/readline/lib
CPPFLAGS: -I/usr/local/opt/readline/include
libedit 来源 rl_bind_key
所以这就是它在 libedit 中不起作用的原因。我下载了源代码,rl_bind_key
函数是这样定义的:
/*
* bind key c to readline-type function func
*/
int
rl_bind_key(int c, rl_command_func_t *func)
{
int retval = -1;
if (h == NULL || e == NULL)
rl_initialize();
if (func == rl_insert) {
/* XXX notice there is no range checking of ``c'' */
e->el_map.key[c] = ED_INSERT;
retval = 0;
}
return retval;
}
所以它似乎被设计为不适用于 rl_insert
以外的任何东西。这似乎是一个错误,而不是一个功能。我希望我知道如何成为 libedit 的贡献者。