tests/comsub28.sub
- new file, contains basic tests for ${; command; }
From a contribution by Kevin Pulo <kevin.pulo@mongodb.com>
+
+ 1/16
+ ----
+lib/readline/complete.c
+ - _rl_internal_pager, get_y_or_n: readline's internal completions
+ pager understands `f' as a synonym for ' ' and `d' to scroll by
+ half the screen height, similar to `less'
+
+lib/readline/complete.c
+ - last_completion_nmatch: new variable, holds the number of matches
+ returned by the last call to rl_complete, set to 0 or 1 as
+ appropriate when we explicitly set last_completion_failed to 0 or 1
+ - rl_complete_internal: if the last completion attempt succeeded and
+ returned multiple matches, but an immediate subsequent completion
+ attempt returned a single match, insert the single match
+ From a report by Adam Purkrt <adampurkrt78@gmail.com> in 5/2025
/* Local variable states what happened during the last completion attempt. */
static int completion_changed_buffer;
static int last_completion_failed = 0;
+static int last_completion_nmatch = 0;
+
+/* Does the vector of possible completions M contain a single match? */
+#define ONEMATCH(m) ((m) && (m)[0] && (m)[1] == 0)
/* The result of the query to the user about displaying completion matches */
static int completion_y_or_n;
rl_possible_completions (int ignore, int invoking_key)
{
last_completion_failed = 0;
+ last_completion_nmatch = 1;
rl_completion_invoking_key = invoking_key;
return (rl_complete_internal ('?'));
}
return (2);
if (for_pager && (c == 'q' || c == 'Q'))
return (0);
+ if (for_pager && c == 'f') /* synonym for ' ' like less */
+ return (1);
+ if (for_pager && c == 'd')
+ return (3);
rl_ding ();
}
}
return -1;
else if (i == 2)
return (lines - 1);
+ else if (i == 3)
+ {
+ int n;
+ n = _rl_screenheight / 2;
+ return (lines > n) ? (lines - n) : -1;
+ }
else
return 0;
}
munge the array, deleting matches as it desires. */
if (rl_ignore_some_completions_function && matching_filenames)
{
- for (nmatch = 1; matches[nmatch]; nmatch++)
- ;
+ nmatch = vector_len (matches);
(void)(*rl_ignore_some_completions_function) (matches);
if (matches == 0 || matches[0] == 0)
{
else
{
/* If we removed some matches, recompute the common prefix. */
- for (i = 1; matches[i]; i++)
- ;
+ i = vector_len (matches);
if (i > 1 && i < nmatch)
{
t = matches[0];
int start, end, delimiter, found_quote, i, nontrivial_lcd, do_display;
char *text, *saved_line_buffer;
char quote_char;
- int tlen, mlen, saved_last_completion_failed;
+ int tlen, mlen, saved_last_completion_failed, saved_last_completion_nmatch;
complete_sigcleanarg_t cleanarg; /* state to clean up on signal */
RL_SETSTATE(RL_STATE_COMPLETING);
saved_last_completion_failed = last_completion_failed;
+ saved_last_completion_nmatch = last_completion_nmatch;
set_completion_defaults (what_to_do);
FREE (saved_line_buffer);
completion_changed_buffer = 0;
last_completion_failed = 1;
+ last_completion_nmatch = 0;
RL_UNSETSTATE(RL_STATE_COMPLETING);
_rl_reset_completion_state ();
return (0);
FREE (saved_line_buffer);
completion_changed_buffer = 0;
last_completion_failed = 1;
+ last_completion_nmatch = 0;
RL_UNSETSTATE(RL_STATE_COMPLETING);
_rl_reset_completion_state ();
return (0);
if (matches && matches[0] && *matches[0])
last_completion_failed = 0;
+ last_completion_nmatch = vector_len (matches);
do_display = 0;
case '?':
/* Let's try to insert a single match here if the last completion failed
but this attempt returned a single match. */
- if (saved_last_completion_failed && matches[0] && *matches[0] && matches[1] == 0)
+ if (saved_last_completion_failed && ONEMATCH (matches))
{
insert_match (matches[0], start, matches[1] ? MULT_MATCH : SINGLE_MATCH, "e_char);
append_to_match (matches[0], delimiter, quote_char, nontrivial_lcd);
break;
}
+ /* Or if the last completion succeeded but returned multiple matches and
+ this attempt returned a single match. */
+ if (saved_last_completion_failed == 0 && saved_last_completion_nmatch > 1 && ONEMATCH (matches))
+ {
+ insert_match (matches[0], start, matches[1] ? MULT_MATCH : SINGLE_MATCH, "e_char);
+ append_to_match (matches[0], delimiter, quote_char, nontrivial_lcd);
+ break;
+ }
+
/*FALLTHROUGH*/
case '%': /* used by menu_complete */