Skip to content

Commit 742b84b

Browse files
authored
Allow Suggestions to be replaced (#955)
* add api to replace completion items * rename SuggestionSources to Suggestions * adding AddSuggestions and AddSuggestion extension methods to OptionExtensions
1 parent f2512fe commit 742b84b

File tree

9 files changed

+144
-98
lines changed

9 files changed

+144
-98
lines changed

src/System.CommandLine.Benchmarks/CommandLine/Perf_Parser_Directives_Suggest.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,16 @@ public void Setup()
2929
new Option("--fruit")
3030
{
3131
Argument = new Argument<string>()
32-
.WithSuggestions("apple", "banana", "cherry")
32+
{
33+
Suggestions = {"apple", "banana", "cherry" }
34+
}
3335
},
3436
new Option("--vegetable")
3537
{
3638
Argument = new Argument<string>()
37-
.WithSuggestions("asparagus", "broccoli", "carrot")
39+
{
40+
Suggestions = {"asparagus", "broccoli", "carrot" }
41+
}
3842
}
3943
};
4044

src/System.CommandLine.Benchmarks/CommandLine/Perf_Suggestions.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,9 @@ public void Setup_FromSymbol()
4141
{
4242
Argument = new Argument
4343
{
44-
Arity = ArgumentArity.ExactlyOne
45-
}
46-
.WithSuggestions(GenerateSuggestionsArray(TestSuggestionsCount))
44+
Arity = ArgumentArity.ExactlyOne,
45+
Suggestions = { GenerateSuggestionsArray(TestSuggestionsCount) }
46+
}
4747
};
4848
}
4949

src/System.CommandLine.Tests/ApprovalTests/Help/HelpBuilderTests.Approval.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ public void Help_describes_default_values_for_complex_root_command_scenario()
6161
Argument = new Argument<FileAccess>("the-root-option-arg", () => FileAccess.Read)
6262
{
6363
Description = "the-root-option-arg-description",
64-
},
64+
}
6565
},
6666
new Option(aliases: new string[] {"--the-root-option-required-enum-arg", "-trorea"}) {
6767
Description = "the-root-option-description",

src/System.CommandLine.Tests/SuggestDirectiveTests.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
33

44
using System.CommandLine.Builder;
5-
using System.CommandLine.Invocation;
65
using System.CommandLine.IO;
76
using System.CommandLine.Parsing;
87
using System.Threading.Tasks;
@@ -23,10 +22,10 @@ public class SuggestDirectiveTests
2322
public SuggestDirectiveTests()
2423
{
2524
_fruitOption = new Option<string>("--fruit")
26-
.WithSuggestions("apple", "banana", "cherry");
25+
.AddSuggestions("apple", "banana", "cherry");
2726

2827
_vegetableOption = new Option<string>("--vegetable")
29-
.WithSuggestions("asparagus", "broccoli", "carrot");
28+
.AddSuggestions("asparagus", "broccoli", "carrot");
3029

3130
_eatCommand = new Command("eat")
3231
{

src/System.CommandLine.Tests/SuggestionTests.cs

Lines changed: 57 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,9 @@ public void Option_Suggest_returns_argument_suggestions_if_configured()
2929
{
3030
Argument = new Argument
3131
{
32-
Arity = ArgumentArity.ExactlyOne
32+
Arity = ArgumentArity.ExactlyOne,
33+
Suggestions = { "one", "two", "three" }
3334
}
34-
.WithSuggestions("one", "two", "three")
3535
};
3636

3737
var suggestions = option.GetSuggestions();
@@ -102,9 +102,9 @@ public void Command_Suggest_returns_available_subcommands_and_option_aliases_and
102102
new Option("--option", "option"),
103103
new Argument
104104
{
105-
Arity = ArgumentArity.OneOrMore
105+
Arity = ArgumentArity.OneOrMore,
106+
Suggestions = { "command-argument" }
106107
}
107-
.WithSuggestions("command-argument")
108108
};
109109

110110
var suggestions = command.GetSuggestions();
@@ -505,9 +505,9 @@ public void Suggestions_can_be_provided_in_the_absence_of_validation()
505505
{
506506
Argument = new Argument
507507
{
508-
Arity = ArgumentArity.ExactlyOne
508+
Arity = ArgumentArity.ExactlyOne,
509+
Suggestions = { "vegetable", "mineral", "animal" }
509510
}
510-
.WithSuggestions("vegetable", "mineral", "animal")
511511
}
512512
};
513513

@@ -529,14 +529,9 @@ public void Command_argument_suggestions_can_be_provided_using_a_delegate()
529529
{
530530
new Argument
531531
{
532-
Arity = ArgumentArity.ExactlyOne
532+
Arity = ArgumentArity.ExactlyOne,
533+
Suggestions = { _ => new[] { "vegetable", "mineral", "animal" } }
533534
}
534-
.WithSuggestionSource(_ => new[]
535-
{
536-
"vegetable",
537-
"mineral",
538-
"animal"
539-
})
540535
}
541536
};
542537

@@ -551,13 +546,13 @@ public void Option_argument_suggestions_can_be_provided_using_a_delegate()
551546
{
552547
var command = new Command("the-command")
553548
{
554-
new Option<string>("-x")
555-
.WithSuggestionSource(_ => new[]
549+
new Option<string>("-x")
550+
{
551+
Argument = new Argument<string>()
556552
{
557-
"vegetable",
558-
"mineral",
559-
"animal"
560-
})
553+
Suggestions = { _ => new[] { "vegetable", "mineral", "animal" } }
554+
}
555+
}
561556
};
562557

563558
var parseResult = command.Parse("the-command -x m");
@@ -997,6 +992,49 @@ public void When_there_are_multiple_arguments_then_suggestions_are_only_offered_
997992
{
998993
Assert.True(false, "Test testname is not written yet.");
999994
}
995+
996+
[Fact]
997+
public void Enum_suggestions_can_be_configured_with_list_clear()
998+
{
999+
var argument = new Argument<DayOfWeek?>();
1000+
argument.Suggestions.Clear();
1001+
argument.Suggestions.Add(new[] { "mon", "tues", "wed", "thur", "fri", "sat", "sun" });
1002+
var command = new Command("the-command")
1003+
{
1004+
argument
1005+
};
1006+
1007+
var suggestions = command.Parse("the-command s")
1008+
.GetSuggestions();
1009+
1010+
suggestions.Should().BeEquivalentTo("sat", "sun","tues");
1011+
}
1012+
1013+
[Fact]
1014+
public void Enum_suggestions_can_be_configured_without_list_clear()
1015+
{
1016+
var command = new Command("the-command")
1017+
{
1018+
new Argument<DayOfWeek?>()
1019+
{
1020+
Suggestions = { "mon", "tues", "wed", "thur", "fri", "sat", "sun" }
1021+
}
1022+
};
1023+
1024+
var suggestions = command.Parse("the-command s")
1025+
.GetSuggestions();
1026+
1027+
suggestions
1028+
.Should()
1029+
.BeEquivalentTo(
1030+
"sat",
1031+
nameof(DayOfWeek.Saturday),
1032+
"sun", nameof(DayOfWeek.Sunday),
1033+
"tues",
1034+
nameof(DayOfWeek.Tuesday),
1035+
nameof(DayOfWeek.Thursday),
1036+
nameof(DayOfWeek.Wednesday));
1037+
}
10001038
}
10011039
}
10021040
}

src/System.CommandLine/Argument.cs

Lines changed: 20 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,6 @@ namespace System.CommandLine
1212
public class Argument : Symbol, IArgument
1313
{
1414
private Func<ArgumentResult, object?>? _defaultValueFactory;
15-
private readonly List<string> _suggestions = new List<string>();
16-
private readonly List<ISuggestionSource> _suggestionSources = new List<ISuggestionSource>();
1715
private IArgumentArity? _arity;
1816
private TryConvertArgument? _convertArguments;
1917
private Type _argumentType = typeof(void);
@@ -109,6 +107,24 @@ bool DefaultConvert(SymbolResult symbol, out object value)
109107
set => _convertArguments = value;
110108
}
111109

110+
111+
private List<ISuggestionSource>? _suggestions = null;
112+
public List<ISuggestionSource> Suggestions
113+
{
114+
get
115+
{
116+
if (_suggestions is null)
117+
{
118+
_suggestions = new List<ISuggestionSource>()
119+
{
120+
SuggestionSource.ForType(ArgumentType)
121+
};
122+
}
123+
124+
return _suggestions;
125+
}
126+
}
127+
112128
public Type ArgumentType
113129
{
114130
get => _argumentType;
@@ -158,36 +174,6 @@ public void SetDefaultValueFactory(Func<ArgumentResult, object?> getDefaultValue
158174

159175
internal static Argument None => new Argument { Arity = ArgumentArity.Zero };
160176

161-
public void AddSuggestions(IReadOnlyCollection<string> suggestions)
162-
{
163-
if (suggestions is null)
164-
{
165-
throw new ArgumentNullException(nameof(suggestions));
166-
}
167-
168-
_suggestions.AddRange(suggestions);
169-
}
170-
171-
public void AddSuggestionSource(ISuggestionSource suggest)
172-
{
173-
if (suggest is null)
174-
{
175-
throw new ArgumentNullException(nameof(suggest));
176-
}
177-
178-
_suggestionSources.Add(suggest);
179-
}
180-
181-
public void AddSuggestionSource(Suggest suggest)
182-
{
183-
if (suggest is null)
184-
{
185-
throw new ArgumentNullException(nameof(suggest));
186-
}
187-
188-
AddSuggestionSource(new AnonymousSuggestionSource(suggest));
189-
}
190-
191177
internal void AddAllowedValues(IEnumerable<string> values)
192178
{
193179
if (AllowedValues is null)
@@ -200,17 +186,10 @@ internal void AddAllowedValues(IEnumerable<string> values)
200186

201187
public override IEnumerable<string?> GetSuggestions(string? textToMatch = null)
202188
{
203-
var fixedSuggestions = _suggestions;
204-
205-
var dynamicSuggestions = _suggestionSources
189+
var dynamicSuggestions = Suggestions
206190
.SelectMany(source => source.GetSuggestions(textToMatch));
207191

208-
var typeSuggestions = SuggestionSource.ForType(ArgumentType)
209-
.GetSuggestions(textToMatch);
210-
211-
return fixedSuggestions
212-
.Concat(dynamicSuggestions)
213-
.Concat(typeSuggestions)
192+
return dynamicSuggestions
214193
.Distinct()
215194
.OrderBy(c => c, StringComparer.OrdinalIgnoreCase)
216195
.Containing(textToMatch);

src/System.CommandLine/ArgumentExtensions.cs

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33

44
using System.Collections.Generic;
55
using System.CommandLine.Parsing;
6-
using System.CommandLine.Suggestions;
76
using System.Linq;
87
using System.IO;
8+
using System.CommandLine.Suggestions;
99

1010
namespace System.CommandLine
1111
{
@@ -17,30 +17,11 @@ public static TArgument FromAmong<TArgument>(
1717
where TArgument : Argument
1818
{
1919
argument.AddAllowedValues(values);
20-
argument.AddSuggestions(values);
20+
argument.Suggestions.Add(values);
2121

2222
return argument;
2323
}
2424

25-
public static TArgument WithSuggestions<TArgument>(
26-
this TArgument argument,
27-
params string[] suggestions)
28-
where TArgument : Argument
29-
{
30-
argument.AddSuggestions(suggestions);
31-
32-
return argument;
33-
}
34-
35-
public static TArgument WithSuggestionSource<TArgument>(
36-
this TArgument argument,
37-
Suggest suggest)
38-
where TArgument : Argument
39-
{
40-
argument.AddSuggestionSource(suggest);
41-
42-
return argument;
43-
}
4425
public static Argument<FileInfo> ExistingOnly(this Argument<FileInfo> argument)
4526
{
4627
argument.AddValidator(symbol =>

src/System.CommandLine/OptionExtensions.cs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) .NET Foundation and contributors. All rights reserved.
1+
// Copyright (c) .NET Foundation and contributors. All rights reserved.
22
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
33

44
using System.Collections.Generic;
@@ -17,27 +17,27 @@ public static TOption FromAmong<TOption>(
1717
where TOption : Option
1818
{
1919
option.Argument.AddAllowedValues(values);
20-
option.Argument.AddSuggestions(values);
20+
option.Argument.Suggestions.Add(values);
2121

2222
return option;
2323
}
2424

25-
public static TOption WithSuggestions<TOption>(
25+
public static TOption AddSuggestions<TOption>(
2626
this TOption option,
27-
params string[] suggestions)
27+
params string[] values)
2828
where TOption : Option
2929
{
30-
option.Argument.AddSuggestions(suggestions);
30+
option.Argument.Suggestions.Add(values);
3131

3232
return option;
3333
}
3434

35-
public static TOption WithSuggestionSource<TOption>(
35+
public static TOption AddSuggestion<TOption>(
3636
this TOption option,
3737
Suggest suggest)
38-
where TOption : Option
38+
where TOption : Option
3939
{
40-
option.Argument.AddSuggestionSource(suggest);
40+
option.Argument.Suggestions.Add(suggest);
4141

4242
return option;
4343
}

0 commit comments

Comments
 (0)