|
1 | | -using System; |
2 | | - |
3 | | -namespace Commands; |
| 1 | +namespace Commands; |
4 | 2 |
|
5 | 3 | /// <summary> |
6 | 4 | /// Represents a mechanism for querying arguments while searching or parsing a command. |
@@ -96,21 +94,27 @@ public Arguments(IEnumerable<KeyValuePair<string, object?>> args) |
96 | 94 | { |
97 | 95 | //_namedArgs = new(comparer); |
98 | 96 |
|
99 | | - int capacityHint = args is ICollection<KeyValuePair<string, object?>> col ? col.Count / 2 : 2; |
100 | | - |
101 | | - List<KeyValuePair<string, object?>> flags = new(capacityHint); |
102 | | - List<string> keys = new(capacityHint); |
| 97 | + var keySet = Array.Empty<string>(); |
| 98 | + var flagSet = Array.Empty<KeyValuePair<string, object?>>(); |
103 | 99 |
|
104 | 100 | foreach (var kvp in args) |
105 | 101 | { |
106 | | - if (kvp.Value is null) |
107 | | - keys.Add(kvp.Key); |
| 102 | + if (kvp.Value == null) |
| 103 | + { |
| 104 | + Array.Resize(ref keySet, keySet.Length + 1); |
| 105 | + |
| 106 | + keySet[keySet.Length - 1] = kvp.Key; |
| 107 | + } |
108 | 108 | else |
109 | | - flags.Add(kvp); |
| 109 | + { |
| 110 | + Array.Resize(ref flagSet, flagSet.Length + 1); |
| 111 | + |
| 112 | + flagSet[flagSet.Length - 1] = kvp; |
| 113 | + } |
110 | 114 | } |
111 | 115 |
|
112 | | - _flaggedKeys = [.. flags]; |
113 | | - _keys = [.. keys]; |
| 116 | + _keys = keySet; |
| 117 | + _flaggedKeys = flagSet; |
114 | 118 |
|
115 | 119 | RemainingLength = _keys.Length + _flaggedKeys.Length; |
116 | 120 | } |
@@ -181,110 +185,145 @@ private readonly bool TryGetValueInternal(string parameterName, out object? valu |
181 | 185 | return false; |
182 | 186 | } |
183 | 187 |
|
184 | | - private static List<KeyValuePair<string, object?>> ReadInternal(string[] input) |
| 188 | + private static IEnumerable<KeyValuePair<string, object?>> ReadInternal(string[] input) |
185 | 189 | { |
186 | | - List<KeyValuePair<string, object?>> result = []; |
| 190 | + if (input.Length is 0) |
| 191 | + yield break; |
187 | 192 |
|
188 | | - if (input.Length == 0) |
189 | | - return result; |
190 | | - |
191 | | - if (input.Length == 1) |
| 193 | + if (input.Length is 1) |
192 | 194 | { |
193 | | - result.Add(new(input[0], null)); |
194 | | - return result; |
| 195 | + yield return new(input[0], null); |
| 196 | + yield break; |
195 | 197 | } |
196 | 198 |
|
197 | | - bool concatenating = false; |
198 | | - string? name = null; |
199 | | - int openQuotes = 0; |
| 199 | + // Reserved for joining arguments. |
| 200 | + var openState = 0; |
| 201 | + var concatenating = false; |
| 202 | + var concatenation = new List<string>(); |
200 | 203 |
|
201 | | - Span<char> buffer = stackalloc char[256]; |
202 | | - ValueStringBuilder vsb = new(buffer); |
| 204 | + // Reserved for named arguments. |
| 205 | + string? name = null; |
203 | 206 |
|
204 | 207 | foreach (var argument in input) |
205 | 208 | { |
206 | | - ReadOnlySpan<char> span = argument.AsSpan(); |
207 | | - |
208 | 209 | if (concatenating) |
209 | 210 | { |
210 | | - if (span[0] == '"') |
211 | | - openQuotes++; |
| 211 | + if (argument.StartsWith(U0022)) |
| 212 | + { |
| 213 | + openState++; |
| 214 | + |
| 215 | + concatenation.Add(argument); |
212 | 216 |
|
213 | | - if (span.Length > 1 && span.Slice(1).IndexOf('"') != -1) |
214 | | - openQuotes--; |
| 217 | + if (argument.Length > 1) |
| 218 | + { |
| 219 | +#if NET8_0_OR_GREATER |
| 220 | + if (argument[1..].Contains(U0022)) |
| 221 | + openState--; |
| 222 | +#else |
| 223 | + if (argument.Remove(0, 1).Contains(U0022)) |
| 224 | + openState--; |
| 225 | +#endif |
| 226 | + } |
215 | 227 |
|
216 | | - vsb.Append(span); |
217 | | - vsb.Append(' '); |
| 228 | + continue; |
| 229 | + } |
218 | 230 |
|
219 | | - if (span[span.Length - 1] == '"') |
| 231 | + if (argument.EndsWith(U0022)) |
220 | 232 | { |
221 | | - openQuotes--; |
222 | | - |
223 | | - if (openQuotes <= 0) |
| 233 | + if (openState is 0) |
224 | 234 | { |
225 | 235 | concatenating = false; |
226 | | - string resultStr = vsb.ToString(); |
| 236 | + |
| 237 | + concatenation.Add(argument); |
227 | 238 |
|
228 | 239 | if (name is null) |
229 | | - result.Add(new(resultStr, null)); |
| 240 | + yield return new(string.Join(U0020, concatenation), null); |
230 | 241 | else |
231 | 242 | { |
232 | | - result.Add(new(name, resultStr)); |
| 243 | + yield return new(name, string.Join(U0020, concatenation)); |
| 244 | + |
233 | 245 | name = null; |
234 | 246 | } |
235 | 247 |
|
236 | | - buffer.Clear(); |
237 | | - vsb = new(buffer); |
| 248 | + concatenation.Clear(); |
| 249 | + } |
| 250 | + else |
| 251 | + { |
| 252 | + openState--; |
| 253 | + |
| 254 | + concatenation.Add(argument); |
238 | 255 | } |
| 256 | + |
| 257 | + continue; |
239 | 258 | } |
240 | 259 |
|
241 | | - continue; |
| 260 | + concatenation.Add(argument); |
242 | 261 | } |
243 | | - |
244 | | - if (span[0] == '-' && span[1] == '-') |
| 262 | + else |
245 | 263 | { |
246 | | - if (name is not null) |
247 | | - result.Add(new(name, null)); |
| 264 | + if (argument.StartsWith(U002D)) |
| 265 | + { |
| 266 | + if (argument.Length > 1) |
| 267 | + { |
| 268 | +#if NET8_0_OR_GREATER |
| 269 | + if (argument[1] is U002D) |
| 270 | + { |
| 271 | + if (name is not null) |
| 272 | + yield return new(name, null); |
248 | 273 |
|
249 | | - name = span.Slice(2).ToString(); |
250 | | - continue; |
251 | | - } |
| 274 | + name = argument[2..]; |
252 | 275 |
|
253 | | - if (span[0] == '"' && span[span.Length - 1] != '"') |
254 | | - { |
255 | | - concatenating = true; |
256 | | - openQuotes = 1; |
| 276 | + continue; |
| 277 | + } |
| 278 | + } |
257 | 279 |
|
258 | | - vsb.Append(span); |
259 | | - vsb.Append(' '); |
260 | | - continue; |
261 | | - } |
| 280 | + yield return new(argument[1..], null); |
| 281 | +#else |
| 282 | + if (argument[1] == U002D[0]) |
| 283 | + { |
| 284 | + if (name is not null) |
| 285 | + yield return new(name, null); |
262 | 286 |
|
263 | | - if (name is null) |
264 | | - { |
265 | | - result.Add(new(argument, null)); |
266 | | - } |
267 | | - else |
268 | | - { |
269 | | - result.Add(new(name, argument)); |
270 | | - name = null; |
271 | | - } |
| 287 | + name = argument.Remove(0, 2); |
272 | 288 |
|
273 | | - buffer.Clear(); |
274 | | - vsb = new(buffer); |
275 | | - } |
| 289 | + continue; |
| 290 | + } |
| 291 | + } |
| 292 | + |
| 293 | + yield return new(argument.Remove(0, 1), null); |
| 294 | +#endif |
| 295 | + |
| 296 | + continue; |
| 297 | + } |
| 298 | + |
| 299 | + if (argument.StartsWith(U0022) && !argument.EndsWith(U0022)) |
| 300 | + { |
| 301 | + concatenating = true; |
| 302 | + |
| 303 | + concatenation.Add(argument); |
276 | 304 |
|
277 | | - string final = vsb.ToString(); |
| 305 | + continue; |
| 306 | + } |
| 307 | + |
| 308 | + if (name is null) |
| 309 | + yield return new(argument, null); |
| 310 | + else |
| 311 | + { |
| 312 | + yield return new(name, argument); |
| 313 | + |
| 314 | + name = null; |
| 315 | + } |
| 316 | + } |
| 317 | + } |
278 | 318 |
|
279 | | - if (final.Length != 0) |
| 319 | + // If concatenation is still filled on escaping the sequence, add as last argument. |
| 320 | + if (concatenation.Count != 0) |
280 | 321 | { |
281 | 322 | if (name is null) |
282 | | - result.Add(new(final, null)); |
| 323 | + yield return new(string.Join(U0020, concatenation), null); |
283 | 324 | else |
284 | | - result.Add(new(name, final)); |
| 325 | + yield return new(name, string.Join(U0020, concatenation)); |
285 | 326 | } |
286 | | - |
287 | | - return result; |
288 | 327 | } |
289 | 328 |
|
290 | 329 | #endregion |
|
0 commit comments