c - 为什么具有自定义函数的 rl_bind_key 在 OSX/macOS 上的 readline 中失败

标签 c macos shell macos-sierra readline

我构建了一个 shell,尝试使用 rl_bind_key() 使 Tab (\t) 键执行自定义操作,但它在 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 似乎 secret 使用了 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 的贡献者。

关于c - 为什么具有自定义函数的 rl_bind_key 在 OSX/macOS 上的 readline 中失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47588197/

相关文章:

windows - lambda 提示符在命令行中表示什么?

linux - Nodejs 更新将旧版本保留为当前版本

perl - 删除数据集中的空行

C - 设置 'popen' 子进程的标准输入 - 跨平台

c++ - arm-linux-androideabi-gcc : get unrecognized command line option when passing -mmacosx-version-min argument

macos - Mac 上的 Python 3 setuptools

html - Google 字体在我使用 Mac 的网站上呈现效果不佳

c - Ubuntu 第一次编译内核模块

c++ - 低级编程 C/C++

c - 如何确定方法函数指针属于 GObject 的实例结构还是类结构?