readline - Changing tab-completion for read builtin in bash -
the current tab-completion while "read -e" active in bash seems matching filenames:
read -e [[tabtab]] abc.txt bcd.txt cde.txt
i want completion set of strings defined me, while file/dir/hostname-completion etc. should deactivated duration of "read -e".
outside of script
complete -w 'string1 string2 string3' -e
works well, cant kind of completion work inside script while using "read -e".
although seems reasonable request, don't believe possible.
the existing implementation of read
builtin sets readline completion environment basic configuration before calling readline handle -e
input.
you can see code in builtins/read.def
, in edit_line
function: sets rl_attempted_completion_function
null
duration of call readline
. readline
has several completion overrides, it's not 100% obvious resets entire completion environment, far know function used implement programmable completion per complete
command.
with work, modify definition of read
command allow specific completion function instead of or in addition readline standard filename completion function. require non-trivial understanding of bash internals, reasonable project if wanted gain familiarity internals.
as simpler less efficient alternative, write own little utility accepts 1 line of keyboard input readline
, echoes stdout. invoke read
redirecting stdin utility:
read -r < <(my_reader string1 string2 string3)
(that assumes my_reader
uses command-line arguments construct potential completion list readline
library. you'd want option present prompt well.)
the readline documentation includes an example of application simple custom completion; once translate k&r function prototype syntax, might pretty easy adapt needs.
edit: after looked @ example again, thought had lot of unnecessary details, wrote following example fewer unnecessary details. might upload github, it's here though it's 100 lines:
#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 1 line using readline, , prints stdout.\n" "returns success if line read.\n" " -p prompt output prompt before requesting input.\n" " -n progname set application name progname readline config file\n" " (default: %s).\n" " -f use filename completion specified completions.\n" " -h print text , exit.\n" " -v print version number , exit.\n" " completion word add list of possible completions.\n", progname); } /* readline likes globals, none of hooks take 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; } /* use if fall 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; (;;) { 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; } /* default stdout, interfere 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; } }
Comments
Post a Comment