mirror of
https://https.git.savannah.gnu.org/git/bash.git
synced 2026-06-22 05:17:59 +02:00
277 lines
8.4 KiB
Plaintext
277 lines
8.4 KiB
Plaintext
/* 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
|
|
rl_complete_internal -- there should be a way to combine the two. Then,
|
|
for each item in the list of matches, we insert the match in an undoable
|
|
fashion, with the appropriate character appended (this happens on the
|
|
second and subsequent consecutive calls to rl_menu_complete). When we
|
|
hit the end of the match list, we restore the original unmatched text,
|
|
ring the bell, and reset the counter to zero. */
|
|
int
|
|
rl_old_menu_complete (count, ignore)
|
|
int count, ignore;
|
|
{
|
|
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;
|
|
static int delimiter;
|
|
|
|
/* The first time through, we generate the list of matches and set things
|
|
up to insert them. */
|
|
if (rl_last_func != rl_menu_complete)
|
|
{
|
|
/* Clean up from previous call, if any. */
|
|
FREE (orig_text);
|
|
if (matches)
|
|
_rl_free_match_list (matches);
|
|
|
|
match_list_index = match_list_size = 0;
|
|
matches = (char **)NULL;
|
|
|
|
/* Only the completion entry function can change these. */
|
|
set_completion_defaults ('%');
|
|
|
|
our_func = rl_menu_completion_entry_function;
|
|
if (our_func == 0)
|
|
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);
|
|
|
|
/* 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++)
|
|
;
|
|
/* matches[0] is lcd if match_list_size > 1, but the circular buffer
|
|
code below should take care of it. */
|
|
|
|
if (match_list_size > 1 && _rl_complete_show_all)
|
|
display_matches (matches);
|
|
}
|
|
|
|
/* 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);
|
|
}
|
|
|
|
match_list_index += count;
|
|
if (match_list_index < 0)
|
|
match_list_index += match_list_size;
|
|
else
|
|
match_list_index %= match_list_size;
|
|
|
|
if (match_list_index == 0 && match_list_size > 1)
|
|
{
|
|
rl_ding ();
|
|
insert_match (orig_text, orig_start, MULT_MATCH, "e_char);
|
|
}
|
|
else
|
|
{
|
|
insert_match (matches[match_list_index], orig_start, SINGLE_MATCH, "e_char);
|
|
append_to_match (matches[match_list_index], delimiter, quote_char,
|
|
strcmp (orig_text, matches[match_list_index]));
|
|
}
|
|
|
|
completion_changed_buffer = 1;
|
|
return (0);
|
|
}
|
|
|
|
int
|
|
rl_menu_complete (count, ignore)
|
|
int count, ignore;
|
|
{
|
|
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 nontrivial_lcd = 0;
|
|
static int full_completion = 0; /* set to 1 if menu completion should reinitialize on next call */
|
|
static int orig_start, orig_end;
|
|
static char quote_char;
|
|
static int delimiter;
|
|
|
|
/* The first time through, we generate the list of matches and set things
|
|
up to insert them. */
|
|
if (rl_last_func != rl_menu_complete || full_completion)
|
|
{
|
|
/* Clean up from previous call, if any. */
|
|
FREE (orig_text);
|
|
if (matches)
|
|
_rl_free_match_list (matches);
|
|
|
|
match_list_index = match_list_size = 0;
|
|
matches = (char **)NULL;
|
|
|
|
full_completion = 0;
|
|
|
|
/* Only the completion entry function can change these. */
|
|
set_completion_defaults ('%');
|
|
|
|
our_func = rl_menu_completion_entry_function;
|
|
if (our_func == 0)
|
|
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++)
|
|
;
|
|
|
|
if (match_list_size == 0)
|
|
{
|
|
rl_ding ();
|
|
FREE (matches);
|
|
matches = (char **)0;
|
|
match_list_index = 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 = orig_start + strlen (matches[0]);
|
|
completion_changed_buffer = STREQ (orig_text, matches[0]) == 0;
|
|
}
|
|
|
|
if (match_list_size > 1 && _rl_complete_show_all)
|
|
{
|
|
display_matches (matches);
|
|
/* If there are so many matches that the user has to be asked
|
|
whether or not he wants to see the matches, menu completion
|
|
is unwieldy. */
|
|
if (rl_completion_query_items > 0 && match_list_size >= rl_completion_query_items)
|
|
{
|
|
rl_ding ();
|
|
FREE (matches);
|
|
matches = (char **)0;
|
|
full_completion = 1;
|
|
return (0);
|
|
}
|
|
}
|
|
else if (match_list_size <= 1)
|
|
{
|
|
append_to_match (matches[0], delimiter, quote_char, nontrivial_lcd);
|
|
full_completion = 1;
|
|
return (0);
|
|
}
|
|
}
|
|
|
|
/* 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);
|
|
}
|
|
|
|
match_list_index += count;
|
|
if (match_list_index < 0)
|
|
match_list_index += match_list_size;
|
|
else
|
|
match_list_index %= match_list_size;
|
|
|
|
if (match_list_index == 0 && match_list_size > 1)
|
|
{
|
|
rl_ding ();
|
|
insert_match (matches[0], orig_start, MULT_MATCH, "e_char);
|
|
}
|
|
else
|
|
{
|
|
insert_match (matches[match_list_index], orig_start, SINGLE_MATCH, "e_char);
|
|
append_to_match (matches[match_list_index], delimiter, quote_char,
|
|
strcmp (orig_text, matches[match_list_index]));
|
|
}
|
|
|
|
completion_changed_buffer = 1;
|
|
return (0);
|
|
}
|