Fix completion failing on unclosed brace with wildcard

Completion on ": {*," used to work but nowadays our attempt to wildcard-expand
it fails with a syntax error and we do nothing.  This behavior probably only
makes sense for the overflow case, so do that.
This commit is contained in:
Johannes Altmanninger 2024-10-19 12:26:44 +02:00
parent f4ff312265
commit cd541575b4
8 changed files with 57 additions and 35 deletions

View File

@ -151,8 +151,10 @@ fn write_part(
)
.result
{
ExpandResultCode::error | ExpandResultCode::wildcard_no_match => {
// Hit expansion limit, forward the unexpanded string.
ExpandResultCode::error
| ExpandResultCode::overflow
| ExpandResultCode::wildcard_no_match => {
// Maybe hit expansion limit, forward the unexpanded string.
args.push(Completion::from_completion(token_text.to_owned()));
}
ExpandResultCode::cancel => {

View File

@ -1566,16 +1566,17 @@ impl<'ctx> Completer<'ctx> {
if let Some(sep_index) = sep_index {
let sep_string = s.slice_from(sep_index + 1);
let mut local_completions = Vec::new();
if expand_string(
sep_string.to_owned(),
&mut local_completions,
flags,
self.ctx,
None,
)
.result
== ExpandResultCode::error
{
if matches!(
expand_string(
sep_string.to_owned(),
&mut local_completions,
flags,
self.ctx,
None,
)
.result,
ExpandResultCode::error | ExpandResultCode::overflow
) {
FLOGF!(complete, "Error while expanding string '%ls'", sep_string);
}
@ -1606,9 +1607,11 @@ impl<'ctx> Completer<'ctx> {
}
let first = self.completions.len();
if expand_to_receiver(s.to_owned(), &mut self.completions, flags, self.ctx, None).result
== ExpandResultCode::error
{
if matches!(
expand_to_receiver(s.to_owned(), &mut self.completions, flags, self.ctx, None)
.result,
ExpandResultCode::error | ExpandResultCode::overflow,
) {
FLOGF!(complete, "Error while expanding string '%ls'", s);
}
Self::escape_opening_brackets(&mut self.completions[first..], s);

View File

@ -1275,14 +1275,20 @@ impl<'a, 'b, 'c> Expander<'a, 'b, 'c> {
}
let this_result = (stage)(&mut expand, comp.completion, &mut output_storage);
total_result = this_result;
if total_result == ExpandResultCode::error {
if matches!(
total_result.result,
ExpandResultCode::error | ExpandResultCode::overflow
) {
break;
}
}
// Output becomes our next stage's input.
completions = output_storage.take();
if total_result == ExpandResultCode::error {
if matches!(
total_result.result,
ExpandResultCode::error | ExpandResultCode::overflow
) {
break;
}
}
@ -1487,7 +1493,7 @@ impl<'a, 'b, 'c> Expander<'a, 'b, 'c> {
let mut expanded = expanded_recv.take();
expanded.sort_by(|a, b| wcsfilecmp_glob(&a.completion, &b.completion));
if !out.extend(expanded) {
result = ExpandResult::new(ExpandResultCode::error);
result = ExpandResult::new(ExpandResultCode::overflow);
}
} else {
// Can't fully justify this check. I think it's that SKIP_WILDCARDS is used when completing
@ -1558,6 +1564,8 @@ impl<'a, 'b, 'c> Expander<'a, 'b, 'c> {
pub enum ExpandResultCode {
/// There was an error, for example, unmatched braces.
error,
/// Expansion would exceed the maximum number of elements.
overflow,
/// Expansion succeeded.
ok,
/// Expansion was cancelled (e.g. control-C).

View File

@ -498,7 +498,7 @@ impl<'a> ExecutionContext {
false,
);
match expand_err.result {
ExpandResultCode::error => {
ExpandResultCode::error | ExpandResultCode::overflow => {
// Issue #5812 - the expansions were done on the command token,
// excluding prefixes such as " " or "if ".
// This means that the error positions are relative to the beginning
@ -630,7 +630,7 @@ impl<'a> ExecutionContext {
variable_assignment.range().unwrap().start() + equals_pos + 1,
);
match expand_ret.result {
ExpandResultCode::error => {
ExpandResultCode::error|ExpandResultCode::overflow => {
return self.report_errors(ctx, expand_ret.status, &errors);
}
ExpandResultCode::cancel => {
@ -1103,7 +1103,7 @@ impl<'a> ExecutionContext {
parse_error_offset_source_start(&mut errors, statement.argument.range().unwrap().start());
match expand_ret.result {
ExpandResultCode::error => {
ExpandResultCode::error | ExpandResultCode::overflow => {
return self.report_errors(ctx, expand_ret.status, &errors);
}
ExpandResultCode::cancel => {
@ -1386,7 +1386,7 @@ impl<'a> ExecutionContext {
);
parse_error_offset_source_start(&mut errors, arg_node.range().unwrap().start());
match expand_ret.result {
ExpandResultCode::error => {
ExpandResultCode::error | ExpandResultCode::overflow => {
return self.report_errors(ctx, expand_ret.status, &errors);
}
ExpandResultCode::cancel => {

View File

@ -1669,15 +1669,18 @@ fn detect_errors_in_decorated_statement(
// Make a new error list so we can fix the offset for just those, then append later.
let mut new_errors = ParseErrorList::new();
let mut command = WString::new();
if expand_to_command_and_args(
unexp_command,
&OperationContext::empty(),
&mut command,
None,
Some(&mut new_errors),
true, /* skip wildcards */
) == ExpandResultCode::error
{
if matches!(
expand_to_command_and_args(
unexp_command,
&OperationContext::empty(),
&mut command,
None,
Some(&mut new_errors),
true, /* skip wildcards */
)
.result,
ExpandResultCode::error | ExpandResultCode::overflow
) {
errored = true;
}

View File

@ -652,9 +652,10 @@ impl Parser {
let list = ast.top().as_freestanding_argument_list().unwrap();
for arg in &list.arguments {
let arg_src = arg.source(arg_list_src);
if expand_string(arg_src.to_owned(), &mut result, flags, ctx, None)
== ExpandResultCode::error
{
if matches!(
expand_string(arg_src.to_owned(), &mut result, flags, ctx, None).result,
ExpandResultCode::error | ExpandResultCode::overflow
) {
break; // failed to expand a string
}
}

View File

@ -5648,7 +5648,8 @@ impl<'a> Reader<'a> {
position_in_token,
&mut wc_expanded,
) {
ExpandResultCode::error => {
ExpandResultCode::error => {}
ExpandResultCode::overflow => {
// This may come about if we exceeded the max number of matches.
// Return "success" to suppress normal completions.
self.flash();

View File

@ -112,3 +112,7 @@ tmux-sleep
isolated-tmux send-keys C-s C-s C-s 'x'
isolated-tmux capture-pane -p
# CHECK: prompt 10> echo do not accept thix
isolated-tmux send-keys C-u C-l ': {*,' Tab Tab Space ,
tmux-sleep
isolated-tmux capture-pane -p
# CHECK: prompt 10> : {*,cmake/ ,{{.*}}