diff -Naur bash-3.2/lib/readline/bind.c bash-3.2-bc/lib/readline/bind.c --- bash-3.2/lib/readline/bind.c 2006-07-27 16:44:10.000000000 +0300 +++ bash-3.2-bc/lib/readline/bind.c 2008-09-04 14:35:44.000000000 +0300 @@ -73,6 +73,8 @@ /* Variables exported by this file. */ Keymap rl_binding_keymap; +extern int rl_completion_y_key; + static char *_rl_read_file PARAMS((char *, size_t *)); static void _rl_init_file_error PARAMS((const char *)); static int _rl_read_init_file PARAMS((const char *, int)); @@ -132,6 +134,10 @@ return (key); } + if (function == rl_browse_complete) { + rl_completion_y_key = key; + } + _rl_keymap[key].type = ISFUNC; _rl_keymap[key].function = function; rl_binding_keymap = _rl_keymap; diff -Naur bash-3.2/lib/readline/complete.c bash-3.2-bc/lib/readline/complete.c --- bash-3.2/lib/readline/complete.c 2006-07-28 18:35:49.000000000 +0300 +++ bash-3.2-bc/lib/readline/complete.c 2008-09-04 15:12:07.000000000 +0300 @@ -246,6 +246,9 @@ this to help determine what kind of completing to do. */ const char *rl_special_prefixes = (const char *)NULL; +/* display matches asked yes / no question */ +int y_n_asked = 0; + /* If non-zero, then disallow duplicates in the matches. */ int rl_ignore_completion_duplicates = 1; @@ -311,6 +314,8 @@ be completed; set before any application completion function is called. */ int rl_completion_found_quote; +int rl_completion_y_key = 0; + /* If non-zero, a slash will be appended to completed filenames that are symbolic links to directory names, subject to the value of the mark-directories variable (which is user-settable). This exists so @@ -424,9 +429,14 @@ c = rl_read_key (); RL_UNSETSTATE(RL_STATE_MOREINPUT); - if (c == 'y' || c == 'Y' || c == ' ') + if (c == 'y' + || c == 'Y' + || c == ' ' + || (rl_completion_y_key && (c == rl_completion_y_key))) return (1); - if (c == 'n' || c == 'N' || c == RUBOUT) + if (c == 'n' + || c == 'N' + || c == RUBOUT) return (0); if (c == ABORT_CHAR) _rl_abort_internal (); @@ -1344,6 +1354,7 @@ } } + /* Display MATCHES, a list of matching filenames in argv format. This handles the simple case -- a single match -- first. If there is more than one match, we compute the number of strings in the list and the @@ -1406,6 +1417,7 @@ rl_crlf (); fprintf (rl_outstream, "Display all %d possibilities? (y or n)", len); fflush (rl_outstream); + y_n_asked = 1; if (get_y_or_n (0) == 0) { rl_crlf (); @@ -2099,6 +2111,150 @@ } } +static struct suggest { + int full_completion; + int browsing; + int match_list_size; + int index; +} suggest = { + .full_completion = 0, + .browsing = 0, + .match_list_size = 0, + .index = 0, +}; + +int +rl_browse_complete (count, key) + int count, key; +{ + rl_compentry_func_t *our_func; + int matching_filenames, found_quote; + + static char *orig_text; + static char **matches = (char **)0; + static int match_list_index = 0; + static int match_list_size = 0; + static int orig_start, orig_end; + static char quote_char = '\0'; + static int delimiter; + static int nontrivial_lcd = 0; + + /* The first time through, we generate the list of matches and set things + up to insert them. */ + if ((rl_last_func != rl_browse_complete) || suggest.full_completion) { + /* Clean up from previous call, if any. */ + FREE (orig_text); + if (matches) + _rl_free_match_list (matches); + suggest.browsing = 0; + suggest.full_completion = 0; + y_n_asked = 0; + + match_list_index = match_list_size = 0; + matches = (char **)NULL; + + /* Only the completion entry function can change these. */ + set_completion_defaults ('%'); + + our_func = rl_completion_entry_function + ? rl_completion_entry_function + : rl_filename_completion_function; + + /* We now look backwards for the start of a filename/variable word. */ + orig_end = rl_point; + found_quote = delimiter = 0; + quote_char = '\0'; + + if (rl_point) { + /* This (possibly) changes rl_point. If it returns a non-zero char, + we know we have an open quote. */ + quote_char = _rl_find_completion_word (&found_quote, &delimiter); + } + + orig_start = rl_point; + rl_point = orig_end; + + orig_text = rl_copy_text (orig_start, orig_end); + matches = gen_completion_matches (orig_text, orig_start, orig_end, + our_func, found_quote, quote_char); + + nontrivial_lcd = matches && strcmp (orig_text, matches[0]) != 0; + + /* If we are matching filenames, the attempted completion function will + have set rl_filename_completion_desired to a non-zero value. The basic + rl_filename_completion_function does this. */ + matching_filenames = rl_filename_completion_desired; + + if (matches == 0 || postprocess_matches (&matches, matching_filenames) == 0) + { + rl_ding (); + FREE (matches); + matches = (char **)0; + FREE (orig_text); + orig_text = (char *)0; + completion_changed_buffer = 0; + return (0); + } + + for (match_list_size = 0; matches[match_list_size]; match_list_size++); + + /* Now we have the list of matches. Replace the text between + rl_line_buffer[orig_start] and rl_line_buffer[rl_point] with + matches[match_list_index], and add any necessary closing char. */ + if (matches == 0 || match_list_size == 0) + { + rl_ding (); + FREE (matches); + matches = (char **)0; + completion_changed_buffer = 0; + return (0); + } + + /* matches[0] is lcd if match_list_size > 1, but the circular buffer + code below should take care of it. */ + + if (*matches[0]) { + insert_match (matches[0], orig_start, matches[1] ? MULT_MATCH : SINGLE_MATCH, "e_char); + orig_end = strlen(matches[0]) + orig_start; + } + + if (match_list_size > 1) { + display_matches (matches); + if (y_n_asked) { + suggest.full_completion = 1; + } else { + suggest.browsing = 1; // proceed to browsing + suggest.match_list_size = match_list_size; + } + suggest.index = 0; + } else { + append_to_match (matches[0], delimiter, quote_char, nontrivial_lcd); + suggest.full_completion = 1; + } + + } else { + if (suggest.browsing) { + if (count < 0) { + if (--suggest.index <= 0) { + suggest.index = suggest.match_list_size -1; + } + } else { + if (++suggest.index >= suggest.match_list_size) { + suggest.index = 1; + } + } + insert_match (matches[suggest.index], orig_start, + SINGLE_MATCH, "e_char); + } else { + completion_changed_buffer = 0; + return 0; + } + } + completion_changed_buffer = 1; + return 0; +} + + /* An initial implementation of a menu completion function a la tcsh. The first time (if the last readline command was not rl_menu_complete), we generate the list of matches. This code is very similar to the code in @@ -2215,3 +2371,4 @@ completion_changed_buffer = 1; return (0); } + diff -Naur bash-3.2/lib/readline/funmap.c bash-3.2-bc/lib/readline/funmap.c --- bash-3.2/lib/readline/funmap.c 2005-03-26 02:23:38.000000000 +0200 +++ bash-3.2-bc/lib/readline/funmap.c 2008-09-04 14:44:18.000000000 +0300 @@ -68,6 +68,7 @@ { "backward-word", rl_backward_word }, { "beginning-of-history", rl_beginning_of_history }, { "beginning-of-line", rl_beg_of_line }, + { "browse-complete", rl_browse_complete }, { "call-last-kbd-macro", rl_call_last_kbd_macro }, { "capitalize-word", rl_capitalize_word }, { "character-search", rl_char_search }, diff -Naur bash-3.2/lib/readline/readline.h bash-3.2-bc/lib/readline/readline.h --- bash-3.2/lib/readline/readline.h 2006-08-16 22:16:59.000000000 +0300 +++ bash-3.2-bc/lib/readline/readline.h 2008-09-04 14:35:57.000000000 +0300 @@ -152,6 +152,7 @@ extern int rl_possible_completions PARAMS((int, int)); extern int rl_insert_completions PARAMS((int, int)); extern int rl_menu_complete PARAMS((int, int)); +extern int rl_browse_complete PARAMS((int, int)); /* Bindable commands for killing and yanking text, and managing the kill ring. */ extern int rl_kill_word PARAMS((int, int));