【问题标题】:Why does rl_bind_key with custom function fail in readline on OSX/macOS为什么具有自定义功能的 rl_bind_key 在 OSX/macOS 上的 readline 中失败
【发布时间】:2017-12-01 07:02:14
【问题描述】:

我构建了一个 shell,尝试使用 rl_bind_key() 使制表符 (\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

此行为的原因是什么,我该如何解决?

【问题讨论】:

    标签: c macos shell macos-sierra readline


    【解决方案1】:

    我使用的是-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 的贡献者。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-12-25
      • 1970-01-01
      • 2018-07-10
      • 2021-03-12
      • 1970-01-01
      • 2012-07-09
      • 2019-04-14
      相关资源
      最近更新 更多