// Copyright 2005-2015 Giacomo Stelluti Scala & Contributors. All rights reserved. See License.md in the project root for license information.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CommandLine.Core;
using CommandLine.Infrastructure;
using CSharpx;
namespace CommandLine
{
///
/// Provides settings for when formatting command line from an options instance../>.
///
public class UnParserSettings
{
private bool preferShortName;
private bool groupSwitches;
private bool useEqualToken;
private bool showHidden;
private bool skipDefault;
///
/// Gets or sets a value indicating whether unparsing process shall prefer short or long names.
///
public bool PreferShortName
{
get { return preferShortName; }
set { PopsicleSetter.Set(Consumed, ref preferShortName, value); }
}
///
/// Gets or sets a value indicating whether unparsing process shall group switches.
///
public bool GroupSwitches
{
get { return groupSwitches; }
set { PopsicleSetter.Set(Consumed, ref groupSwitches, value); }
}
///
/// Gets or sets a value indicating whether unparsing process shall use equal sign with long names.
///
public bool UseEqualToken
{
get { return useEqualToken; }
set { PopsicleSetter.Set(Consumed, ref useEqualToken, value); }
}
///
/// Gets or sets a value indicating whether unparsing process shall expose hidden options.
///
public bool ShowHidden
{
get { return showHidden; }
set { PopsicleSetter.Set(Consumed, ref showHidden, value); }
}
///
/// Gets or sets a value indicating whether unparsing process shall skip options with DefaultValue.
///
public bool SkipDefault
{
get { return skipDefault; }
set { PopsicleSetter.Set(Consumed, ref skipDefault, value); }
}
///
/// Factory method that creates an instance of with GroupSwitches set to true.
///
/// A properly initalized instance.
public static UnParserSettings WithGroupSwitchesOnly()
{
return new UnParserSettings { GroupSwitches = true };
}
///
/// Factory method that creates an instance of with UseEqualToken set to true.
///
/// A properly initalized instance.
public static UnParserSettings WithUseEqualTokenOnly()
{
return new UnParserSettings { UseEqualToken = true };
}
internal bool Consumed { get; set; }
}
///
/// Provides overloads to unparse options instance.
///
public static class UnParserExtensions
{
///
/// Format a command line argument string from a parsed instance.
///
/// Type of .
/// Parser instance.
/// A parsed (or manually correctly constructed instance).
/// A string with command line arguments.
public static string FormatCommandLine(this Parser parser, T options)
{
return parser.FormatCommandLine(options, config => { });
}
///
/// Format a command line argument string from a parsed instance in the form of string[].
///
/// Type of .
/// Parser instance.
/// A parsed (or manually correctly constructed instance).
/// A string[] with command line arguments.
public static string[] FormatCommandLineArgs(this Parser parser, T options)
{
return parser.FormatCommandLine(options, config => { }).SplitArgs();
}
///
/// Format a command line argument string from a parsed instance.
///
/// Type of .
/// Parser instance.
/// A parsed (or manually correctly constructed instance).
/// The lambda used to configure
/// aspects and behaviors of the unparsersing process.
/// A string with command line arguments.
public static string FormatCommandLine(this Parser parser, T options, Action configuration)
{
if (options == null) throw new ArgumentNullException("options");
var settings = new UnParserSettings();
configuration(settings);
settings.Consumed = true;
var type = options.GetType();
var builder = new StringBuilder();
type.GetVerbSpecification()
.MapValueOrDefault(verb => builder.Append(verb.Name).Append(' '), builder);
var specs =
(from info in
type.GetSpecifications(
pi => new
{
Specification = Specification.FromProperty(pi),
Value = pi.GetValue(options, null).NormalizeValue(),
PropertyValue = pi.GetValue(options, null)
})
where !info.PropertyValue.IsEmpty(info.Specification, settings.SkipDefault)
select info)
.Memoize();
var allOptSpecs = from info in specs.Where(i => i.Specification.Tag == SpecificationType.Option)
let o = (OptionSpecification)info.Specification
where o.TargetType != TargetType.Switch ||
(o.TargetType == TargetType.Switch && o.FlagCounter && ((int)info.Value > 0)) ||
(o.TargetType == TargetType.Switch && ((bool)info.Value))
where !o.Hidden || settings.ShowHidden
orderby o.UniqueName()
select info;
var shortSwitches = from info in allOptSpecs
let o = (OptionSpecification)info.Specification
where o.TargetType == TargetType.Switch
where o.ShortName.Length > 0
orderby o.UniqueName()
select info;
var optSpecs = settings.GroupSwitches
? allOptSpecs.Where(info => !shortSwitches.Contains(info))
: allOptSpecs;
var valSpecs = from info in specs.Where(i => i.Specification.Tag == SpecificationType.Value)
let v = (ValueSpecification)info.Specification
orderby v.Index
select info;
builder = settings.GroupSwitches && shortSwitches.Any()
? builder.Append('-').Append(string.Join(string.Empty, shortSwitches.Select(
info => {
var o = (OptionSpecification)info.Specification;
return o.FlagCounter
? string.Concat(Enumerable.Repeat(o.ShortName, (int)info.Value))
: o.ShortName;
}).ToArray())).Append(' ')
: builder;
optSpecs.ForEach(
opt =>
builder
.Append(FormatOption((OptionSpecification)opt.Specification, opt.Value, settings))
.Append(' ')
);
builder.AppendWhen(valSpecs.Any() && parser.Settings.EnableDashDash, "-- ");
valSpecs.ForEach(
val => builder.Append(FormatValue(val.Specification, val.Value)).Append(' '));
return builder
.ToString().TrimEnd(' ');
}
///
/// Format a command line argument string[] from a parsed instance.
///
/// Type of .
/// Parser instance.
/// A parsed (or manually correctly constructed instance).
/// The lambda used to configure
/// aspects and behaviors of the unparsersing process.
/// A string[] with command line arguments.
public static string[] FormatCommandLineArgs(this Parser parser, T options, Action configuration)
{
return FormatCommandLine(parser, options, configuration).SplitArgs();
}
private static string FormatValue(Specification spec, object value)
{
var builder = new StringBuilder();
switch (spec.TargetType)
{
case TargetType.Scalar:
builder.Append(FormatWithQuotesIfString(value));
break;
case TargetType.Sequence:
var sep = spec.SeperatorOrSpace();
Func