Skip to content

Commit a3ef302

Browse files
committed
fix(completion): a regression on flags without a long name
1 parent ac8689b commit a3ef302

File tree

3 files changed

+46
-80
lines changed

3 files changed

+46
-80
lines changed

crates/nu-cli/src/completions/completer.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -396,10 +396,12 @@ impl NuCompleter {
396396
// unfinished argument completion for commands
397397
match &element_expression.expr {
398398
Expr::Call(call) => {
399+
let signature = working_set.get_decl(call.decl_id).signature();
399400
// NOTE: the argument to complete is not necessarily the last one
400401
// for lsp completion, we don't trim the text,
401402
// so that `def`s after pos can be completed
402403
let mut positional_arg_indices = Vec::new();
404+
403405
for (arg_idx, arg) in call.arguments.iter().enumerate() {
404406
let span = arg.span();
405407

@@ -411,8 +413,6 @@ impl NuCompleter {
411413
continue;
412414
}
413415

414-
let signature = working_set.get_decl(call.decl_id).signature();
415-
416416
// Get custom completion from PositionalArg or Flag
417417
let completion = {
418418
// Check PositionalArg or Flag from Signature

crates/nu-cli/tests/completions/mod.rs

Lines changed: 41 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -272,91 +272,54 @@ fn customcompletions_no_sort() {
272272
match_suggestions(&expected, &suggestions);
273273
}
274274

275+
#[rstest]
275276
/// Fallback to file completions if custom completer returns null
276-
#[test]
277-
fn customcompletions_fallback() {
278-
let (_, _, mut engine, mut stack) = new_engine();
279-
let command = r#"
280-
def comp [] { null }
281-
def my-command [arg: string@comp] {}"#;
282-
assert!(support::merge_input(command.as_bytes(), &mut engine, &mut stack).is_ok());
283-
284-
let mut completer = NuCompleter::new(Arc::new(engine), Arc::new(stack));
285-
let completion_str = "my-command test";
286-
let suggestions = completer.complete(completion_str, completion_str.len());
287-
let expected = [folder("test_a"), file("test_a_symlink"), folder("test_b")];
288-
match_suggestions_by_string(&expected, &suggestions);
289-
}
290-
277+
#[case::fallback(r#"
278+
def comp [] { null }
279+
def my-command [arg: string@comp] {}"#,
280+
"my-command test",
281+
vec![folder("test_a"), file("test_a_symlink"), folder("test_b")]
282+
)]
291283
/// Custom function arguments mixed with subcommands
292-
#[test]
293-
fn custom_arguments_and_subcommands() {
294-
let (_, _, mut engine, mut stack) = new_engine();
295-
let command = r#"
296-
def foo [i: directory] {}
297-
def "foo test bar" [] {}"#;
298-
assert!(support::merge_input(command.as_bytes(), &mut engine, &mut stack).is_ok());
299-
300-
let mut completer = NuCompleter::new(Arc::new(engine), Arc::new(stack));
301-
let completion_str = "foo test";
302-
let suggestions = completer.complete(completion_str, completion_str.len());
303-
// including both subcommand and directory completions
304-
let expected = [
305-
folder("test_a"),
306-
file("test_a_symlink"),
307-
folder("test_b"),
308-
"foo test bar".into(),
309-
];
310-
match_suggestions_by_string(&expected, &suggestions);
311-
}
312-
313-
/// Custom function flags mixed with subcommands
314-
#[test]
315-
fn custom_flags_and_subcommands() {
316-
let (_, _, mut engine, mut stack) = new_engine();
317-
let command = r#"
318-
def foo [--test: directory] {}
319-
def "foo --test bar" [] {}"#;
320-
assert!(support::merge_input(command.as_bytes(), &mut engine, &mut stack).is_ok());
321-
322-
let mut completer = NuCompleter::new(Arc::new(engine), Arc::new(stack));
323-
let completion_str = "foo --test";
324-
let suggestions = completer.complete(completion_str, completion_str.len());
325-
// including both flag and directory completions
326-
let expected: Vec<_> = vec!["--test", "foo --test bar"];
327-
match_suggestions(&expected, &suggestions);
328-
}
329-
284+
#[case::arguments_and_subcommands(r#"
285+
def foo [i: directory] {}
286+
def "foo test bar" [] {}"#,
287+
"foo test",
288+
vec![folder("test_a"), file("test_a_symlink"), folder("test_b"), "foo test bar".into()]
289+
)]
330290
/// If argument type is something like int/string, complete only subcommands
331-
#[test]
332-
fn custom_arguments_vs_subcommands() {
291+
#[case::arguments_vs_subcommands(r#"
292+
def foo [i: string] {}
293+
def "foo test bar" [] {}"#,
294+
"foo test",
295+
vec!["foo test bar".into()]
296+
)]
297+
/// Custom function flags mixed with subcommands
298+
#[case::flags_and_subcommands(r#"
299+
def foo [--test: directory] {}
300+
def "foo --test bar" [] {}"#,
301+
"foo --test",
302+
vec!["--test".into(), "foo --test bar".into()]
303+
)]
304+
#[case::defined_inline(
305+
"",
306+
"export def say [
307+
animal: string@[cat dog]
308+
] { }; say ",
309+
vec!["cat".into(), "dog".into()]
310+
)]
311+
#[case::short_flags(
312+
"def foo [-A, -B: string@[cat dog] ] {}",
313+
"foo -B ",
314+
vec!["cat".into(), "dog".into()]
315+
)]
316+
fn custom_completions(#[case] command: &str, #[case] input: &str, #[case] expected: Vec<String>) {
333317
let (_, _, mut engine, mut stack) = new_engine();
334-
let command = r#"
335-
def foo [i: string] {}
336-
def "foo test bar" [] {}"#;
337318
assert!(support::merge_input(command.as_bytes(), &mut engine, &mut stack).is_ok());
338319

339320
let mut completer = NuCompleter::new(Arc::new(engine), Arc::new(stack));
340-
let completion_str = "foo test";
341-
let suggestions = completer.complete(completion_str, completion_str.len());
342-
// including only subcommand completions
343-
let expected: Vec<_> = vec!["foo test bar"];
344-
match_suggestions(&expected, &suggestions);
345-
}
346-
347-
#[test]
348-
fn custom_completions_defined_inline() {
349-
let (_, _, engine, stack) = new_engine();
350-
351-
let mut completer = NuCompleter::new(Arc::new(engine), Arc::new(stack));
352-
let completion_str = "def animals [] { [cat dog] }
353-
export def say [
354-
animal: string@animals
355-
] { }; say ";
356-
let suggestions = completer.complete(completion_str, completion_str.len());
357-
// including only subcommand completions
358-
let expected: Vec<_> = vec!["cat", "dog"];
359-
match_suggestions(&expected, &suggestions);
321+
let suggestions = completer.complete(input, input.len());
322+
match_suggestions_by_string(&expected, &suggestions);
360323
}
361324

362325
#[test]

crates/nu-protocol/src/signature.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -806,6 +806,9 @@ impl Signature {
806806

807807
/// Find the matching long flag
808808
pub fn get_long_flag(&self, name: &str) -> Option<Flag> {
809+
if name.is_empty() {
810+
return None;
811+
}
809812
for flag in &self.named {
810813
if flag.long == name {
811814
return Some(flag.clone());

0 commit comments

Comments
 (0)