-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathcompletion_result.dart
More file actions
260 lines (232 loc) · 8.18 KB
/
completion_result.dart
File metadata and controls
260 lines (232 loc) · 8.18 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
import 'package:args/args.dart';
import 'package:cli_completion/parser.dart';
import 'package:meta/meta.dart';
/// {@template completion_result}
/// Describes the result of a completion handling process.
/// {@endtemplate}
///
/// Generated after parsing a completion request from the shell, it is
/// responsible to contain the information to be sent back to the shell
/// (via stdout) including suggestions and its metadata (description).
///
/// See also:
/// - [AllOptionsAndCommandsCompletionResult]
/// - [AllAbbrOptionsCompletionResult]
/// - [MatchingCommandsCompletionResult]
/// - [MatchingOptionsCompletionResult]
/// - [OptionValuesCompletionResult]
@immutable
abstract class CompletionResult {
/// {@macro completion_result}
const CompletionResult();
/// A collection of [MapEntry] with completion suggestions to their
/// descriptions.
Map<String, String?> get completions;
}
/// {@template all_options_and_commands_completion_result}
/// A [CompletionResult] that suggests all options and commands in a
/// [completionLevel].
/// {@endtemplate}
class AllOptionsAndCommandsCompletionResult extends CompletionResult {
/// {@macro all_options_and_commands_completion_result}
const AllOptionsAndCommandsCompletionResult({
required this.completionLevel,
});
/// The [CompletionLevel] in which the suggested options and subcommands are
/// supposed to be located at.
final CompletionLevel completionLevel;
@override
Map<String, String?> get completions {
final mapCompletions = <String, String?>{};
for (final subcommand in completionLevel.visibleSubcommands) {
mapCompletions[subcommand.name] = subcommand.description;
}
for (final option in completionLevel.visibleOptions) {
mapCompletions['--${option.name}'] = option.help;
if (option.negatable ?? false) {
mapCompletions['--no-${option.name}'] = option.help;
}
}
return mapCompletions;
}
}
/// {@template all_options_and_commands_completion_result}
/// A [CompletionResult] that suggests all abbreviated options in a
/// [completionLevel].
/// {@endtemplate}
///
/// See also:
/// - [AllOptionsAndCommandsCompletionResult]
class AllAbbrOptionsCompletionResult extends CompletionResult {
/// {@macro all_options_and_commands_completion_result}
const AllAbbrOptionsCompletionResult({
required this.completionLevel,
});
/// The [CompletionLevel] in which the suggested options and subcommands are
/// supposed to be located at.
final CompletionLevel completionLevel;
@override
Map<String, String?> get completions {
final mapCompletions = <String, String?>{};
for (final option in completionLevel.visibleOptions) {
final abbr = option.abbr;
if (abbr != null) {
mapCompletions['-$abbr'] = option.help;
}
}
return mapCompletions;
}
}
/// {@template matching_commands_completion_result}
/// A [CompletionResult] that suggests the sub commands in a [completionLevel]
/// that matches [pattern] (A.K.A: startsWith).
/// {@endtemplate}
///
/// If a command doesnt match the pattern, its aliases are also checked.
class MatchingCommandsCompletionResult extends CompletionResult {
/// {@macro matching_commands_completion_result}
const MatchingCommandsCompletionResult({
required this.completionLevel,
required this.pattern,
});
/// The [CompletionLevel] in which the suggested commands are supposed to be
/// located at.
final CompletionLevel completionLevel;
/// The pattern in which the matching commands will be suggested.
final String pattern;
@override
Map<String, String?> get completions {
final mapCompletions = <String, String>{};
for (final command in completionLevel.visibleSubcommands) {
final description = command.description;
if (command.name.startsWith(pattern)) {
mapCompletions[command.name] = description;
} else {
for (final alias in command.aliases) {
if (alias.startsWith(pattern)) {
mapCompletions[alias] = description;
}
}
}
}
return mapCompletions;
}
}
/// {@template matching_options_completion_result}
/// A [CompletionResult] that suggests the options in a [completionLevel] that
/// starts with [pattern].
/// {@endtemplate}
///
/// If an option does not match the pattern, its aliases will be checked.
class MatchingOptionsCompletionResult extends CompletionResult {
/// {@macro matching_options_completion_result}
const MatchingOptionsCompletionResult({
required this.completionLevel,
required this.pattern,
});
/// The [CompletionLevel] in which the suggested options are supposed to be
/// located at.
final CompletionLevel completionLevel;
/// The pattern in which the matching options will be suggested.
final String pattern;
@override
Map<String, String?> get completions {
final mapCompletions = <String, String?>{};
for (final option in completionLevel.visibleOptions) {
final isNegatable = option.negatable ?? false;
if (isNegatable) {
if (option.negatedName.startsWith(pattern)) {
mapCompletions['--${option.negatedName}'] = option.help;
} else {
for (final negatedAlias in option.negatedAliases) {
if (negatedAlias.startsWith(pattern)) {
mapCompletions['--$negatedAlias'] = option.help;
}
}
}
}
if (option.name.startsWith(pattern)) {
mapCompletions['--${option.name}'] = option.help;
} else {
for (final alias in option.aliases) {
if (alias.startsWith(pattern)) {
mapCompletions['--$alias'] = option.help;
}
}
}
}
return mapCompletions;
}
}
/// {@template option_values_completion_result}
/// A [CompletionResult] that suggests the values of an option given its
/// [optionName] and its [completionLevel].
/// {@endtemplate}
///
/// For options with [Option.allowed] values, the suggestions will be those
/// values with [Option.allowedHelp] as description.
///
/// If [pattern] is not null, only the values that start with the pattern will
/// be suggested.
///
/// Use [OptionValuesCompletionResult.isAbbr] to suggest the values of an option
/// in an abbreviated form.
class OptionValuesCompletionResult extends CompletionResult {
/// {@macro option_values_completion_result}
const OptionValuesCompletionResult({
required this.completionLevel,
required this.optionName,
this.pattern,
}) : isAbbr = false,
includeAbbrName = false;
/// {@macro option_values_completion_result}
const OptionValuesCompletionResult.abbr({
required this.completionLevel,
required String abbrName,
this.pattern,
this.includeAbbrName = false,
}) : isAbbr = true,
optionName = abbrName;
/// The [CompletionLevel] in which the suggested option is supposed to be
/// located at.
final CompletionLevel completionLevel;
/// The pattern in which the matching options values be suggested.
final String? pattern;
/// The name of the option whose values will be suggested.
final String optionName;
/// Whether the option name is abbreviated.
final bool isAbbr;
/// Whether the option name should be included in the suggestions.
/// This is only used when [isAbbr] is true.
///
/// If true, suggestions will look like `-psomething` where `p` is the
/// abbreviated option name and `something` is the suggested value.
final bool includeAbbrName;
@override
Map<String, String?> get completions {
final Option? option;
if (isAbbr) {
option = completionLevel.grammar.findByAbbreviation(optionName);
} else {
option = completionLevel.grammar.findByNameOrAlias(optionName);
}
final allowed = option?.allowed ?? [];
Iterable<String> filteredAllowed;
if (pattern == null) {
filteredAllowed = allowed;
} else {
filteredAllowed = allowed.where((e) => e.startsWith(pattern!));
}
return {
for (final allowed in filteredAllowed)
if (includeAbbrName)
'-$optionName$allowed': option?.allowedHelp?[allowed]
else
allowed: option?.allowedHelp?[allowed],
};
}
}
extension on Option {
String get negatedName => 'no-$name';
Iterable<String> get negatedAliases => aliases.map((e) => 'no-$e');
}