Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multiple long args #887

Open
wants to merge 3 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/CommandLine/Core/InstanceBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ public static ParserResult<T> Build<T>(
var missingValueErrors = from token in errorsPartition
select
new MissingValueOptionError(
optionSpecs.Single(o => token.Text.MatchName(o.ShortName, o.LongName, nameComparer))
optionSpecs.Single(o => token.Text.MatchName(o.ShortName, o.LongNames, nameComparer))
.FromOptionSpecification());

var specPropsWithValue =
Expand Down
7 changes: 4 additions & 3 deletions src/CommandLine/Core/NameExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,23 +1,24 @@
// Copyright 2005-2015 Giacomo Stelluti Scala & Contributors. All rights reserved. See License.md in the project root for license information.

using System;
using System.Linq;

namespace CommandLine.Core
{
static class NameExtensions
{
public static bool MatchName(this string value, string shortName, string longName, StringComparer comparer)
public static bool MatchName(this string value, string shortName, string[] longNames, StringComparer comparer)
{
return value.Length == 1
? comparer.Equals(value, shortName)
: comparer.Equals(value, longName);
: longNames.Any(longName => comparer.Equals(value, longName));
}

public static NameInfo FromOptionSpecification(this OptionSpecification specification)
{
return new NameInfo(
specification.ShortName,
specification.LongName);
specification.LongNames);
}

public static NameInfo FromSpecification(this Specification specification)
Expand Down
4 changes: 2 additions & 2 deletions src/CommandLine/Core/NameLookup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ static class NameLookup
{
public static NameLookupResult Contains(string name, IEnumerable<OptionSpecification> specifications, StringComparer comparer)
{
var option = specifications.FirstOrDefault(a => name.MatchName(a.ShortName, a.LongName, comparer));
var option = specifications.FirstOrDefault(a => name.MatchName(a.ShortName, a.LongNames, comparer));
if (option == null) return NameLookupResult.NoOptionFound;
return option.ConversionType == typeof(bool) || (option.ConversionType == typeof(int) && option.FlagCounter)
? NameLookupResult.BooleanOptionFound
Expand All @@ -29,7 +29,7 @@ public static Maybe<char> HavingSeparator(string name, IEnumerable<OptionSpecifi
StringComparer comparer)
{
return specifications.SingleOrDefault(
a => name.MatchName(a.ShortName, a.LongName, comparer) && a.Separator != '\0')
a => name.MatchName(a.ShortName, a.LongNames, comparer) && a.Separator != '\0')
.ToMaybe()
.MapValueOrDefault(spec => Maybe.Just(spec.Separator), Maybe.Nothing<char>());
}
Expand Down
2 changes: 1 addition & 1 deletion src/CommandLine/Core/OptionMapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public static Result<
pt =>
{
var matched = options.Where(s =>
s.Key.MatchName(((OptionSpecification)pt.Specification).ShortName, ((OptionSpecification)pt.Specification).LongName, comparer)).ToMaybe();
s.Key.MatchName(((OptionSpecification)pt.Specification).ShortName, ((OptionSpecification)pt.Specification).LongNames, comparer)).ToMaybe();
if (matched.IsJust())
{
var matches = matched.GetValueOrDefault(Enumerable.Empty<KeyValuePair<string, IEnumerable<string>>>());
Expand Down
30 changes: 25 additions & 5 deletions src/CommandLine/Core/OptionSpecification.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace CommandLine.Core
sealed class OptionSpecification : Specification
{
private readonly string shortName;
private readonly string longName;
private readonly string[] longNames;
private readonly char separator;
private readonly string setName;
private readonly string group;
Expand All @@ -23,7 +23,21 @@ public OptionSpecification(string shortName, string longName, bool required, str
required, min, max, defaultValue, helpText, metaValue, enumValues, conversionType, conversionType == typeof(int) && flagCounter ? TargetType.Switch : targetType, hidden)
{
this.shortName = shortName;
this.longName = longName;
this.longNames = new [] { longName };
this.separator = separator;
this.setName = setName;
this.group = group;
this.flagCounter = flagCounter;
}

public OptionSpecification(string shortName, string[] longNames, bool required, string setName, Maybe<int> min, Maybe<int> max,
char separator, Maybe<object> defaultValue, string helpText, string metaValue, IEnumerable<string> enumValues,
Type conversionType, TargetType targetType, string group, bool flagCounter = false, bool hidden = false)
: base(SpecificationType.Option,
required, min, max, defaultValue, helpText, metaValue, enumValues, conversionType, conversionType == typeof(int) && flagCounter ? TargetType.Switch : targetType, hidden)
{
this.shortName = shortName;
this.longNames = longNames;
this.separator = separator;
this.setName = setName;
this.group = group;
Expand All @@ -34,7 +48,7 @@ public static OptionSpecification FromAttribute(OptionAttribute attribute, Type
{
return new OptionSpecification(
attribute.ShortName,
attribute.LongName,
attribute.LongNames,
attribute.Required,
attribute.SetName,
attribute.Min == -1 ? Maybe.Nothing<int>() : Maybe.Just(attribute.Min),
Expand All @@ -57,14 +71,20 @@ public static OptionSpecification NewSwitch(string shortName, string longName, b
'\0', Maybe.Nothing<object>(), helpText, metaValue, Enumerable.Empty<string>(), typeof(bool), TargetType.Switch, string.Empty, false, hidden);
}

public static OptionSpecification NewSwitch(string shortName, string[] longNames, bool required, string helpText, string metaValue, bool hidden = false)
{
return new OptionSpecification(shortName, longNames, required, string.Empty, Maybe.Nothing<int>(), Maybe.Nothing<int>(),
'\0', Maybe.Nothing<object>(), helpText, metaValue, Enumerable.Empty<string>(), typeof(bool), TargetType.Switch, string.Empty, false, hidden);
}

public string ShortName
{
get { return shortName; }
}

public string LongName
public string[] LongNames
{
get { return longName; }
get { return longNames; }
}

public char Separator
Expand Down
2 changes: 1 addition & 1 deletion src/CommandLine/Core/Specification.cs
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ public static Specification FromProperty(PropertyInfo property)
var spec = OptionSpecification.FromAttribute(oa.Single(), property.PropertyType,
ReflectionHelper.GetNamesOfEnum(property.PropertyType));

if (spec.ShortName.Length == 0 && spec.LongName.Length == 0)
if (spec.ShortName.Length == 0 && spec.LongNames.Length == 0)
{
return spec.WithLongName(property.Name.ToLowerInvariant());
}
Expand Down
4 changes: 2 additions & 2 deletions src/CommandLine/Core/SpecificationExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public static OptionSpecification WithLongName(this OptionSpecification specific
{
return new OptionSpecification(
specification.ShortName,
newLongName,
new [] { newLongName },
specification.Required,
specification.SetName,
specification.Min,
Expand All @@ -41,7 +41,7 @@ public static OptionSpecification WithLongName(this OptionSpecification specific

public static string UniqueName(this OptionSpecification specification)
{
return specification.ShortName.Length > 0 ? specification.ShortName : specification.LongName;
return specification.ShortName.Length > 0 ? specification.ShortName : specification.LongNames[0];
}

public static IEnumerable<Specification> ThrowingValidate(this IEnumerable<Specification> specifications, IEnumerable<Tuple<Func<Specification, bool>, string>> guardsLookup)
Expand Down
7 changes: 6 additions & 1 deletion src/CommandLine/Core/SpecificationGuards.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

using System;
using System.Collections.Generic;
using System.Linq;
using CSharpx;

namespace CommandLine.Core
Expand Down Expand Up @@ -30,7 +31,11 @@ private static Func<Specification, bool> GuardAgainstSequenceWithWrongRange()

private static Func<Specification, bool> GuardAgainstOneCharLongName()
{
return spec => spec.IsOption() && ((OptionSpecification)spec).LongName.Length == 1;
return spec =>
{
var optionSpecification = spec as OptionSpecification;
return spec.IsOption() && (optionSpecification?.LongNames.Any(x => x.Length == 1) ?? false);
};
}

private static Func<Specification, bool> GuardAgainstSequenceWithZeroRange()
Expand Down
15 changes: 7 additions & 8 deletions src/CommandLine/Core/SpecificationPropertyRules.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ where o.Group.Length > 0
if (options.Any())
{
return from o in options
select new GroupOptionAmbiguityError(new NameInfo(o.ShortName, o.LongName));
select new GroupOptionAmbiguityError(new NameInfo(o.ShortName, o.LongNames));
}

return Enumerable.Empty<Error>();
Expand Down Expand Up @@ -79,7 +79,7 @@ group o by o.Option.Group into g

if (errorGroups.Any())
{
return errorGroups.Select(gr => new MissingGroupOptionError(gr.Key, gr.Select(g => new NameInfo(g.Option.ShortName, g.Option.LongName))));
return errorGroups.Select(gr => new MissingGroupOptionError(gr.Key, gr.Select(g => new NameInfo(g.Option.ShortName, g.Option.LongNames))));
}

return Enumerable.Empty<Error>();
Expand Down Expand Up @@ -199,20 +199,19 @@ where t.IsName()
join o in specs on t.Text equals o.ShortName into to
from o in to.DefaultIfEmpty()
where o != null
select new { o.ShortName, o.LongName };
select new { o.ShortName, o.LongNames };
var longOptions = from t in tokens
where t.IsName()
join o in specs on t.Text equals o.LongName into to
from o in to.DefaultIfEmpty()
where o != null
select new { o.ShortName, o.LongName };
from o in specs
where o.LongNames.Contains(t.Text)
select new { o.ShortName, o.LongNames };
var groups = from x in shortOptions.Concat(longOptions)
group x by x into g
let count = g.Count()
select new { Value = g.Key, Count = count };
var errors = from y in groups
where y.Count > 1
select new RepeatedOptionError(new NameInfo(y.Value.ShortName, y.Value.LongName));
select new RepeatedOptionError(new NameInfo(y.Value.ShortName, y.Value.LongNames));
return errors;
};
}
Expand Down
4 changes: 2 additions & 2 deletions src/CommandLine/Core/TypeLookup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public static Maybe<TypeDescriptor> FindTypeDescriptorAndSibling(
StringComparer comparer)
{
var info =
specifications.SingleOrDefault(a => name.MatchName(a.ShortName, a.LongName, comparer))
specifications.SingleOrDefault(a => name.MatchName(a.ShortName, a.LongNames, comparer))
.ToMaybe()
.Map(
first =>
Expand All @@ -31,4 +31,4 @@ public static Maybe<TypeDescriptor> FindTypeDescriptorAndSibling(

}
}
}
}
48 changes: 36 additions & 12 deletions src/CommandLine/NameInfo.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright 2005-2015 Giacomo Stelluti Scala & Contributors. All rights reserved. See License.md in the project root for license information.

using System;
using CommandLine.Core;
using System.Linq;

namespace CommandLine
{
Expand All @@ -14,16 +14,40 @@ public sealed class NameInfo : IEquatable<NameInfo>
/// Represents an empty name information. Used when <see cref="CommandLine.Error"/> are tied to values,
/// rather than options.
/// </summary>
public static readonly NameInfo EmptyName = new NameInfo(string.Empty, string.Empty);
private readonly string longName;
public static readonly NameInfo EmptyName = new NameInfo(string.Empty, new string[0]);
private readonly string[] longNames;
private readonly string shortName;

internal NameInfo(string shortName)
{
if (shortName == null) throw new ArgumentNullException("shortName");

this.longNames = new string[0];
this.shortName = shortName;
}

internal NameInfo(string shortName, string longName)
{
if (shortName == null) throw new ArgumentNullException("shortName");
if (longName == null) throw new ArgumentNullException("longName");
if (longName == string.Empty)
{
this.longNames = new string[0];
}
else
{
this.longNames = new [] { longName };
}

this.longName = longName;
this.shortName = shortName;
}

internal NameInfo(string shortName, string[] longNames)
{
if (shortName == null) throw new ArgumentNullException("shortName");
if (longNames == null) throw new ArgumentNullException("longNames");
if (longNames.Any(x => x == null)) throw new ArgumentNullException("longNames");
this.longNames = longNames;
this.shortName = shortName;
}

Expand All @@ -38,9 +62,9 @@ public string ShortName
/// <summary>
/// Gets the long name of the name information.
/// </summary>
public string LongName
public string[] LongNames
{
get { return longName; }
get { return longNames; }
}

/// <summary>
Expand All @@ -50,11 +74,11 @@ public string NameText
{
get
{
return ShortName.Length > 0 && LongName.Length > 0
? ShortName + ", " + LongName
return ShortName.Length > 0 && LongNames.Length > 0
? ShortName + ", " + string.Join(", ", LongNames)
: ShortName.Length > 0
? ShortName
: LongName;
: string.Join(", ", LongNames);
}
}

Expand All @@ -80,7 +104,7 @@ public override bool Equals(object obj)
/// <remarks>A hash code for the current <see cref="System.Object"/>.</remarks>
public override int GetHashCode()
{
return new { ShortName, LongName }.GetHashCode();
return CSharpx.EnumerableExtensions.Prepend(LongNames, ShortName).ToArray().GetHashCode();
}

/// <summary>
Expand All @@ -95,7 +119,7 @@ public bool Equals(NameInfo other)
return false;
}

return ShortName.Equals(other.ShortName) && LongName.Equals(other.LongName);
return ShortName.Equals(other.ShortName) && LongNames.SequenceEqual(other.LongNames);
}
}
}
}
Loading