Skip to content

Commit e0f68c6

Browse files
Rob Nasbymoh-hassan
Rob Nasby
authored andcommitted
Properly assign arguments after a double dash to values, rather than options.
1 parent 959d3b2 commit e0f68c6

File tree

5 files changed

+64
-77
lines changed

5 files changed

+64
-77
lines changed

src/CommandLine/Core/Sequence.cs

Lines changed: 5 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ public static IEnumerable<Token> Partition(
3333
break;
3434

3535
case SequenceState.TokenFound:
36-
if (token.IsValue())
36+
//IsValueForced are tokens after --
37+
if (token.IsValue() && !token.IsValueForced())
3738
{
3839
if (sequences.TryGetValue(nameToken, out var sequence))
3940
{
@@ -66,85 +67,16 @@ public static IEnumerable<Token> Partition(
6667

6768
foreach (var kvp in sequences)
6869
{
70+
6971
yield return kvp.Key;
7072
foreach (var value in kvp.Value)
7173
{
7274
yield return value;
7375
}
74-
}
75-
76-
//return from tseq in tokens.Pairwise(
77-
//(f, s) =>
78-
// f.IsName() && s.IsValue()
79-
// ? typeLookup(f.Text).MapValueOrDefault(info =>
80-
// info.TargetType == TargetType.Sequence
81-
// ? new[] { f }.Concat(tokens.OfSequence(f, info))
82-
// : new Token[] { }, new Token[] { })
83-
// : new Token[] { })
84-
// from t in tseq
85-
// select t;
76+
}
8677
}
8778

88-
//private static IEnumerable<Token> OfSequence(this IEnumerable<Token> tokens, Token nameToken, TypeDescriptor info)
89-
//{
90-
// var state = SequenceState.TokenSearch;
91-
// var count = 0;
92-
// var max = info.MaxItems.GetValueOrDefault(int.MaxValue);
93-
// var values = max != int.MaxValue
94-
// ? new List<Token>(max)
95-
// : new List<Token>();
96-
97-
// foreach (var token in tokens)
98-
// {
99-
// if (count == max)
100-
// {
101-
// break;
102-
// }
103-
104-
// switch (state)
105-
// {
106-
// case SequenceState.TokenSearch:
107-
// if (token.IsName() && token.Text.Equals(nameToken.Text))
108-
// {
109-
// state = SequenceState.TokenFound;
110-
// }
111-
// break;
112-
113-
// case SequenceState.TokenFound:
114-
// if (token.IsValue())
115-
// {
116-
// state = SequenceState.ValueFound;
117-
// count++;
118-
// values.Add(token);
119-
// }
120-
// else
121-
// {
122-
// // Invalid to provide option without value
123-
// return Enumerable.Empty<Token>();
124-
// }
125-
// break;
126-
127-
// case SequenceState.ValueFound:
128-
// if (token.IsValue())
129-
// {
130-
// count++;
131-
// values.Add(token);
132-
// }
133-
// else if (token.IsName() && token.Text.Equals(nameToken.Text))
134-
// {
135-
// state = SequenceState.TokenFound;
136-
// }
137-
// else
138-
// {
139-
// state = SequenceState.TokenSearch;
140-
// }
141-
// break;
142-
// }
143-
// }
144-
145-
// return values;
146-
//}
147-
79+
14880
private enum SequenceState
14981
{
15082
TokenSearch,

src/CommandLine/Core/Token.cs

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,11 @@ public static Token Value(string text, bool explicitlyAssigned)
3232
return new Value(text, explicitlyAssigned);
3333
}
3434

35+
public static Token ValueForced(string text)
36+
{
37+
return new Value(text, false, true);
38+
}
39+
3540
public TokenType Tag
3641
{
3742
get { return tag; }
@@ -80,23 +85,35 @@ public bool Equals(Name other)
8085
class Value : Token, IEquatable<Value>
8186
{
8287
private readonly bool explicitlyAssigned;
88+
private readonly bool forced;
8389

8490
public Value(string text)
85-
: this(text, false)
91+
: this(text, false, false)
8692
{
8793
}
8894

8995
public Value(string text, bool explicitlyAssigned)
96+
: this(text, explicitlyAssigned, false)
97+
{
98+
}
99+
100+
public Value(string text, bool explicitlyAssigned, bool forced)
90101
: base(TokenType.Value, text)
91102
{
92103
this.explicitlyAssigned = explicitlyAssigned;
104+
this.forced = forced;
93105
}
94106

95107
public bool ExplicitlyAssigned
96108
{
97109
get { return explicitlyAssigned; }
98110
}
99111

112+
public bool Forced
113+
{
114+
get { return forced; }
115+
}
116+
100117
public override bool Equals(object obj)
101118
{
102119
var other = obj as Value;
@@ -120,7 +137,7 @@ public bool Equals(Value other)
120137
return false;
121138
}
122139

123-
return Tag.Equals(other.Tag) && Text.Equals(other.Text);
140+
return Tag.Equals(other.Tag) && Text.Equals(other.Text) && this.Forced == other.Forced;
124141
}
125142
}
126143

@@ -135,5 +152,10 @@ public static bool IsValue(this Token token)
135152
{
136153
return token.Tag == TokenType.Value;
137154
}
155+
156+
public static bool IsValueForced(this Token token)
157+
{
158+
return token.IsValue() && ((Value)token).Forced;
159+
}
138160
}
139-
}
161+
}

src/CommandLine/Core/Tokenizer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ public static Result<IEnumerable<Token>, Error> PreprocessDashDash(
5050
if (arguments.Any(arg => arg.EqualsOrdinal("--")))
5151
{
5252
var tokenizerResult = tokenizer(arguments.TakeWhile(arg => !arg.EqualsOrdinal("--")));
53-
var values = arguments.SkipWhile(arg => !arg.EqualsOrdinal("--")).Skip(1).Select(Token.Value);
53+
var values = arguments.SkipWhile(arg => !arg.EqualsOrdinal("--")).Skip(1).Select(Token.ValueForced);
5454
return tokenizerResult.Map(tokens => tokens.Concat(values));
5555
}
5656
return tokenizer(arguments);
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
using System.Collections.Generic;
2+
3+
namespace CommandLine.Tests.Fakes
4+
{
5+
public class Options_With_Option_Sequence_And_Value_Sequence
6+
{
7+
[Option('o', "option-seq")]
8+
public IEnumerable<string> OptionSequence { get; set; }
9+
10+
[Value(0)]
11+
public IEnumerable<string> ValueSequence { get; set; }
12+
}
13+
}

tests/CommandLine.Tests/Unit/ParserTests.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,26 @@ public void Parse_options_with_double_dash()
132132
// Teardown
133133
}
134134

135+
[Fact]
136+
public void Parse_options_with_double_dash_and_option_sequence()
137+
{
138+
var expectedOptions = new Options_With_Option_Sequence_And_Value_Sequence
139+
{
140+
OptionSequence = new[] { "option1", "option2", "option3" },
141+
ValueSequence = new[] { "value1", "value2", "value3" }
142+
};
143+
144+
var sut = new Parser(with => with.EnableDashDash = true);
145+
146+
// Exercize system
147+
var result =
148+
sut.ParseArguments<Options_With_Option_Sequence_And_Value_Sequence>(
149+
new[] { "--option-seq", "option1", "option2", "option3", "--", "value1", "value2", "value3" });
150+
151+
// Verify outcome
152+
((Parsed<Options_With_Option_Sequence_And_Value_Sequence>)result).Value.Should().BeEquivalentTo(expectedOptions);
153+
}
154+
135155
[Fact]
136156
public void Parse_options_with_double_dash_in_verbs_scenario()
137157
{

0 commit comments

Comments
 (0)