BadScript 2
Loading...
Searching...
No Matches
UnParserExtensions.cs
Go to the documentation of this file.
1// Copyright 2005-2015 Giacomo Stelluti Scala & Contributors. All rights reserved. See License.md in the project root for license information.
2
3using System;
4using System.Collections;
5using System.Linq;
6using System.Text;
7
10
11using CSharpx;
12
13namespace CommandLine
14{
18 public class UnParserSettings
19 {
20 private bool groupSwitches;
21 private bool preferShortName;
22 private bool showHidden;
23 private bool skipDefault;
24 private bool useEqualToken;
25
29 public bool PreferShortName
30 {
31 get => preferShortName;
32 set => PopsicleSetter.Set(Consumed, ref preferShortName, value);
33 }
34
38 public bool GroupSwitches
39 {
40 get => groupSwitches;
41 set => PopsicleSetter.Set(Consumed, ref groupSwitches, value);
42 }
43
47 public bool UseEqualToken
48 {
49 get => useEqualToken;
50 set => PopsicleSetter.Set(Consumed, ref useEqualToken, value);
51 }
52
56 public bool ShowHidden
57 {
58 get => showHidden;
59 set => PopsicleSetter.Set(Consumed, ref showHidden, value);
60 }
61
65 public bool SkipDefault
66 {
67 get => skipDefault;
68 set => PopsicleSetter.Set(Consumed, ref skipDefault, value);
69 }
70
71 internal bool Consumed { get; set; }
72
79 {
80 return new UnParserSettings { GroupSwitches = true };
81 }
82
89 {
90 return new UnParserSettings { UseEqualToken = true };
91 }
92 }
93
97 public static class UnParserExtensions
98 {
106 public static string FormatCommandLine<T>(this Parser parser, T options)
107 {
108 return parser.FormatCommandLine(options, config => { });
109 }
110
118 public static string[] FormatCommandLineArgs<T>(this Parser parser, T options)
119 {
120 return parser.FormatCommandLine(options, config => { })
121 .SplitArgs();
122 }
123
135 public static string FormatCommandLine<T>(this Parser parser, T options, Action<UnParserSettings> configuration)
136 {
137 if (options == null)
138 {
139 throw new ArgumentNullException("options");
140 }
141
142 UnParserSettings settings = new UnParserSettings();
143 configuration(settings);
144 settings.Consumed = true;
145
146 Type type = options.GetType();
147 StringBuilder builder = new StringBuilder();
148
149 type.GetVerbSpecification()
150 .MapValueOrDefault(verb => builder.Append(verb.Name)
151 .Append(' '),
152 builder
153 );
154
155 var specs =
156 (from info in
157 type.GetSpecifications(pi => new
158 {
160 Value = pi.GetValue(options, null)
161 .NormalizeValue(),
162 PropertyValue = pi.GetValue(options, null),
163 }
164 )
165 where !info.PropertyValue.IsEmpty(info.Specification, settings.SkipDefault)
166 select info)
167 .Memoize();
168
169 var allOptSpecs = from info in specs.Where(i => i.Specification.Tag == SpecificationType.Option)
170 let o = (OptionSpecification)info.Specification
171 where o.TargetType != TargetType.Switch ||
172 (o.TargetType == TargetType.Switch && o.FlagCounter && (int)info.Value > 0) ||
173 (o.TargetType == TargetType.Switch && (bool)info.Value)
174 where !o.Hidden || settings.ShowHidden
175 orderby o.UniqueName()
176 select info;
177
178 var shortSwitches = from info in allOptSpecs
179 let o = (OptionSpecification)info.Specification
180 where o.TargetType == TargetType.Switch
181 where o.ShortName.Length > 0
182 orderby o.UniqueName()
183 select info;
184
185 var optSpecs = settings.GroupSwitches
186 ? allOptSpecs.Where(info => !shortSwitches.Contains(info))
187 : allOptSpecs;
188
189 var valSpecs = from info in specs.Where(i => i.Specification.Tag == SpecificationType.Value)
190 let v = (ValueSpecification)info.Specification
191 orderby v.Index
192 select info;
193
194 builder = settings.GroupSwitches && shortSwitches.Any()
195 ? builder.Append('-')
196 .Append(string.Join(string.Empty,
197 shortSwitches.Select(info =>
198 {
199 OptionSpecification o =
200 (OptionSpecification)info
201 .Specification;
202
203 return o.FlagCounter
204 ? string
205 .Concat(Enumerable
206 .Repeat(o.ShortName,
207 (int)info.Value
208 )
209 )
210 : o.ShortName;
211 }
212 )
213 .ToArray()
214 )
215 )
216 .Append(' ')
217 : builder;
218
219 optSpecs.ForEach(opt =>
220 builder
221 .Append(FormatOption((OptionSpecification)opt.Specification, opt.Value, settings))
222 .Append(' ')
223 );
224
225 builder.AppendWhen(valSpecs.Any() && parser.Settings.EnableDashDash, "-- ");
226
227 valSpecs.ForEach(val => builder.Append(FormatValue(val.Specification, val.Value))
228 .Append(' ')
229 );
230
231 return builder
232 .ToString()
233 .TrimEnd(' ');
234 }
235
247 public static string[] FormatCommandLineArgs<T>(this Parser parser,
248 T options,
249 Action<UnParserSettings> configuration)
250 {
251 return FormatCommandLine(parser, options, configuration)
252 .SplitArgs();
253 }
254
255 private static string FormatValue(Specification spec, object value)
256 {
257 StringBuilder builder = new StringBuilder();
258
259 switch (spec.TargetType)
260 {
261 case TargetType.Scalar:
262 builder.Append(FormatWithQuotesIfString(value));
263
264 break;
265 case TargetType.Sequence:
266 char sep = spec.SeperatorOrSpace();
267
268 Func<object, object> format = v
269 => sep == ' ' ? FormatWithQuotesIfString(v) : v;
270 IEnumerator e = ((IEnumerable)value).GetEnumerator();
271
272 while (e.MoveNext())
273 {
274 builder.Append(format(e.Current))
275 .Append(sep);
276 }
277
278 builder.TrimEndIfMatch(sep);
279
280 break;
281 }
282
283 return builder.ToString();
284 }
285
286 private static object FormatWithQuotesIfString(object value)
287 {
288 string s = value.ToString();
289
290 if (!string.IsNullOrEmpty(s) && !s.Contains("\"") && s.Contains(" "))
291 {
292 return $"\"{s}\"";
293 }
294
295 Func<string, string> doubQt = v
296 => v.Contains("\"") ? v.Replace("\"", "\\\"") : v;
297
298 return s.ToMaybe()
299 .MapValueOrDefault(v => v.Contains(' ') || v.Contains("\"")
300 ? "\"".JoinTo(doubQt(v), "\"")
301 : v,
302 value
303 );
304 }
305
306 private static char SeperatorOrSpace(this Specification spec)
307 {
308 return (spec as OptionSpecification).ToMaybe()
309 .MapValueOrDefault(o => o.Separator != '\0' ? o.Separator : ' ', ' ');
310 }
311
312 private static string FormatOption(OptionSpecification spec, object value, UnParserSettings settings)
313 {
314 return new StringBuilder()
315 .Append(spec.FormatName(value, settings))
316 .AppendWhen(spec.TargetType != TargetType.Switch, FormatValue(spec, value))
317 .ToString();
318 }
319
320 private static string FormatName(this OptionSpecification optionSpec, object value, UnParserSettings settings)
321 {
322 // Have a long name and short name not preferred? Go with long!
323 // No short name? Has to be long!
324 bool longName = (optionSpec.LongName.Length > 0 && !settings.PreferShortName) ||
325 optionSpec.ShortName.Length == 0;
326
327 string formattedName =
328 new StringBuilder(longName
329 ? "--".JoinTo(optionSpec.LongName)
330 : "-".JoinTo(optionSpec.ShortName)
331 )
332 .AppendWhen(optionSpec.TargetType != TargetType.Switch,
333 longName && settings.UseEqualToken ? "=" : " "
334 )
335 .ToString();
336
337 return optionSpec.FlagCounter
338 ? string.Join(" ", Enumerable.Repeat(formattedName, (int)value))
339 : formattedName;
340 }
341
342 private static object NormalizeValue(this object value)
343 {
344#if !SKIP_FSHARP
345 if (value != null
346 && ReflectionHelper.IsFSharpOptionType(value.GetType())
347 && FSharpOptionHelper.IsSome(value))
348 {
349 return FSharpOptionHelper.ValueOf(value);
350 }
351#endif
352 return value;
353 }
354
355 private static bool IsEmpty(this object value, Specification specification, bool skipDefault)
356 {
357 if (value == null)
358 {
359 return true;
360 }
361
362 if (skipDefault && value.Equals(specification.DefaultValue.FromJust()))
363 {
364 return true;
365 }
366
367 if (Nullable.GetUnderlyingType(specification.ConversionType) != null)
368 {
369 return false; //nullable
370 }
371
372#if !SKIP_FSHARP
373 if (ReflectionHelper.IsFSharpOptionType(value.GetType()) && !FSharpOptionHelper.IsSome(value)) return true;
374#endif
375 if (value is ValueType &&
376 value.Equals(value.GetType()
377 .GetDefaultValue()
378 ))
379 {
380 return true;
381 }
382
383 if (value is string && ((string)value).Length == 0)
384 {
385 return true;
386 }
387
388 if (value is IEnumerable &&
389 !((IEnumerable)value).GetEnumerator()
390 .MoveNext())
391 {
392 return true;
393 }
394
395 return false;
396 }
397
398
399#region splitter
400
408 public static string[] SplitArgs(this string command, bool keepQuote = false)
409 {
410 if (string.IsNullOrEmpty(command))
411 {
412 return new string[0];
413 }
414
415 bool inQuote = false;
416
417 char[] chars = command.ToCharArray()
418 .Select(v =>
419 {
420 if (v == '"')
421 {
422 inQuote = !inQuote;
423 }
424
425 return !inQuote && v == ' ' ? '\n' : v;
426 }
427 )
428 .ToArray();
429
430 return new string(chars).Split('\n')
431 .Select(x => keepQuote ? x : x.Trim('"'))
432 .Where(x => !string.IsNullOrWhiteSpace(x))
433 .ToArray();
434 }
435
436#endregion
437 }
438}
static Specification FromProperty(PropertyInfo property)
Type ConversionType
This information is denormalized to decouple Specification from PropertyInfo.
Provides methods to parse command line arguments.
Definition Parser.cs:21
ParserSettings Settings
Gets the instance that implements CommandLine.ParserSettings in use.
Definition Parser.cs:80
bool EnableDashDash
Gets or sets a value indicating whether enable double dash '–' syntax, that forces parsing of all sub...
Provides overloads to unparse options instance.
static string[] SplitArgs(this string command, bool keepQuote=false)
Returns a string array that contains the substrings in this instance that are delimited by space cons...
static bool IsEmpty(this object value, Specification specification, bool skipDefault)
static string FormatName(this OptionSpecification optionSpec, object value, UnParserSettings settings)
static string FormatValue(Specification spec, object value)
static object FormatWithQuotesIfString(object value)
static string FormatOption(OptionSpecification spec, object value, UnParserSettings settings)
static object NormalizeValue(this object value)
static string[] FormatCommandLineArgs< T >(this Parser parser, T options)
Format a command line argument string from a parsed instance in the form of string[].
static string FormatCommandLine< T >(this Parser parser, T options)
Format a command line argument string from a parsed instance.
static char SeperatorOrSpace(this Specification spec)
Provides settings for when formatting command line from an options instance../>.
static UnParserSettings WithGroupSwitchesOnly()
Factory method that creates an instance of CommandLine.UnParserSettings with GroupSwitches set to tru...
bool PreferShortName
Gets or sets a value indicating whether unparsing process shall prefer short or long names.
bool UseEqualToken
Gets or sets a value indicating whether unparsing process shall use equal sign with long names.
bool ShowHidden
Gets or sets a value indicating whether unparsing process shall expose hidden options.
bool SkipDefault
Gets or sets a value indicating whether unparsing process shall skip options with DefaultValue.
static UnParserSettings WithUseEqualTokenOnly()
Factory method that creates an instance of CommandLine.UnParserSettings with UseEqualToken set to tru...
bool GroupSwitches
Gets or sets a value indicating whether unparsing process shall group switches.