2016-01-07 3 views
2

Текущей закладки-завершение, а «чтения -e» активен в Баше, кажется, сравниваться только имена файлов:Изменение вкладки-завершения для чтения в Баше встроенных

read -e 
[[TabTab]] 
abc.txt bcd.txt cde.txt 

хочет завершение быть множеством строки, определенные мной, в то время как file/dir/hostname-completion и т. д. должны деактивироваться на время «read -e».

Вне сценария

complete -W 'string1 string2 string3' -E 

работает хорошо, но я не могу получить этот вид завершения работы внутри сценария, используя «чтения -e».

+0

Когда вы смотрите «автодополнение внутри сценария», вы используете текстовый редактор, чтобы написать сценарий? I.e., это не в подсказке bash, а внутри vim/emacs/etc.? – chrisaycock

+0

Вы запустили эту команду завершения внутри своего скрипта? Или просто верьте, что он был установлен в среде? (Помогает ли использование 'complete -E -W ....'?Документация заставляет это звучать, как порядок может иметь значение, хотя, вероятно, это не так.) –

+1

@chrisaycock Я думаю, что OP означает, что 'read -e' запускается из сценария не использует это завершение. –

ответ

2

Хотя это кажется разумным запросом, я не считаю, что это возможно.

Существующая реализация встроенного комплекса read устанавливает среду завершения чтения в довольно базовую конфигурацию перед вызовом readline для обработки ввода -e.

Вы можете увидеть код в builtins/read.def, в edit_line function: она устанавливает rl_attempted_completion_function в NULL на время вызова readline. readline имеет несколько переопределений завершения, поэтому на 100% очевидно, что это сбрасывает всю среду завершения, но насколько я знаю, это функция, которая используется для реализации программируемого завершения согласно команде complete.

С некоторыми работами вы, вероятно, можете изменить определение команды read, чтобы разрешить определенную функцию завершения вместо или в дополнение к стандартной функции завершения имени файла readline. Для этого потребуется нетривиальное понимание внутренних элементов bash, но это был бы разумный проект, если бы вы хотели получить знакомство с этими внутренностями.

Как простая, но менее эффективная альтернатива, вы можете написать свою собственную небольшую утилиту, которая просто принимает одну строку ввода с клавиатуры с readline и перекликается с ней на стандартный вывод. Затем вызовите read перенаправляют его стандартный ввод в ваши утилиты:.

read -r < <(my_reader string1 string2 string3) 

(Это предполагает, что my_reader использует свои аргументы командной строки для построения потенциального списка завершения для readline библиотеки Вы, вероятно, хотите возможность представить запрос а также.)

В документацию readline входит an example of an application, которая выполняет простую настройку; как только вы переводите его из синтаксиса прототипа функции R 0 0 0 0 0 0 0 0 32


Edit: После я снова посмотрел на этот пример, я думал, что это было много ненужных деталей, поэтому я написал следующий пример с меньшим количеством ненужных деталей. Я мог бы загрузить его на GitHub, но теперь он здесь, хотя это почти 100 строк:

#include <stdbool.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <unistd.h> 

#include <readline/readline.h> 

static void version(const char* progname) { 
    fprintf(stderr, "%s 0.1\n", progname); 
} 
static void usage(const char* progname) { 
    fprintf(stderr, "Usage: %s [-fhv] [-p PROMPT] [-n PROGNAME] [COMPLETION...]\n", progname); 
    fprintf(stderr, 
      "Reads one line using readline, and prints it to stdout.\n" 
      "Returns success if a line was read.\n" 
      " -p PROMPT Output PROMPT before requesting input.\n" 
      " -n PROGNAME Set application name to PROGNAME for readline config file\n" 
      "    (Default: %s).\n" 
      " -f   Use filename completion as well as specified completions.\n" 
      " -h   Print this help text and exit.\n" 
      " -v   Print version number and exit.\n" 
      " COMPLETION word to add to the list of possible completions.\n", 
      progname); 
} 

/* Readline really likes globals, so none of its hooks take a context parameter. */ 
static char** completions = NULL; 
static char* generate_next_completion(const char* text, int state) { 
    static int index = 0; 
    if (state == 0) index = 0; /* reset index if we're starting */ 
    size_t textlen = strlen(text); 
    while (completions[index++]) 
    if (strncmp(completions[index - 1], text, textlen) == 0) 
     return strdup(completions[index - 1]); 
    return NULL; 
} 

/* We use this if we will fall back to filename completion */ 
static char** generate_completions(const char* text, int start, int end) { 
    return rl_completion_matches(text, generate_next_completion); 
} 

int main (int argc, char **argv) { 
    const char* prompt = ""; 
    const char* progname = strrchr(argv[0], '/'); 
    progname = progname ? progname + 1 : argv[0]; 
    rl_readline_name = progname; 

    bool use_file_completion = false; 

    for (;;) { 
    int opt = getopt(argc, argv, "+fp:n:hv"); 
    switch (opt) { 
     case -1: break; 
     case 'f': use_file_completion = true; continue; 
     case 'p': prompt = optarg; continue; 
     case 'n': rl_readline_name = optarg; continue; 
     case 'h': usage(progname); return 0; 
     case 'v': version(progname); return 0; 
     default: usage(progname); return 2; 
    } 
    break; 
    } 

    /* The default is stdout, which would interfere with capturing output. */ 
    rl_outstream = stderr; 

    completions = argv + optind; 
    rl_completion_entry_function = rl_filename_completion_function; 
    if (*completions) { 
    if (use_file_completion) 
     rl_attempted_completion_function = generate_completions; 
    else 
     rl_completion_entry_function = generate_next_completion; 
    } else { 
    /* No specified strings */ 
    if (!use_file_completion) 
     rl_inhibit_completion = true; 
    } 

    char* line = readline(prompt); 

    if (line) { 
    puts(line); 
    free(line); 
    return 0; 
    } else { 
    fputc('\n', rl_outstream); 
    return 1; 
    } 
}