Skip to content

Commit b6d3d47

Browse files
Rob Nasbyrmunn
Rob Nasby
authored andcommitted
Properly assign arguments after a double dash to values, rather than options.
1 parent ee77b84 commit b6d3d47

File tree

6 files changed

+67
-16
lines changed

6 files changed

+67
-16
lines changed

src/CommandLine/Core/Scalar.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ public static IEnumerable<Token> Partition(
1616
{
1717
return from tseq in tokens.Pairwise(
1818
(f, s) =>
19-
f.IsName() && s.IsValue()
19+
f.IsName() && s.IsValueUnforced()
2020
? typeLookup(f.Text).MapValueOrDefault(info =>
2121
info.TargetType == TargetType.Scalar ? new[] { f, s } : new Token[] { }, new Token[] { })
2222
: new Token[] { })

src/CommandLine/Core/Sequence.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public static IEnumerable<Token> Partition(
3333
break;
3434

3535
case SequenceState.TokenFound:
36-
if (token.IsValue())
36+
if (token.IsValueUnforced())
3737
{
3838
if (sequences.TryGetValue(nameToken, out var sequence))
3939
{

src/CommandLine/Core/Token.cs

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,14 @@ public static Token Value(string text)
2727
return new Value(text);
2828
}
2929

30-
public static Token Value(string text, bool explicitlyAssigned)
30+
public static Token Value(string text, bool forced)
3131
{
32-
return new Value(text, explicitlyAssigned);
32+
return new Value(text, forced);
33+
}
34+
35+
public static Token ValueForced(string text)
36+
{
37+
return new Value(text, true);
3338
}
3439

3540
public TokenType Tag
@@ -79,22 +84,22 @@ public bool Equals(Name other)
7984

8085
class Value : Token, IEquatable<Value>
8186
{
82-
private readonly bool explicitlyAssigned;
87+
private readonly bool forced;
8388

8489
public Value(string text)
8590
: this(text, false)
8691
{
8792
}
8893

89-
public Value(string text, bool explicitlyAssigned)
94+
public Value(string text, bool forced)
9095
: base(TokenType.Value, text)
9196
{
92-
this.explicitlyAssigned = explicitlyAssigned;
97+
this.forced = forced;
9398
}
9499

95-
public bool ExplicitlyAssigned
100+
public bool Forced
96101
{
97-
get { return explicitlyAssigned; }
102+
get { return forced; }
98103
}
99104

100105
public override bool Equals(object obj)
@@ -110,7 +115,7 @@ public override bool Equals(object obj)
110115

111116
public override int GetHashCode()
112117
{
113-
return new { Tag, Text }.GetHashCode();
118+
return new { Tag, Text, Forced }.GetHashCode();
114119
}
115120

116121
public bool Equals(Value other)
@@ -120,7 +125,7 @@ public bool Equals(Value other)
120125
return false;
121126
}
122127

123-
return Tag.Equals(other.Tag) && Text.Equals(other.Text);
128+
return Tag.Equals(other.Tag) && Text.Equals(other.Text) && this.Forced == other.Forced;
124129
}
125130
}
126131

@@ -135,5 +140,15 @@ public static bool IsValue(this Token token)
135140
{
136141
return token.Tag == TokenType.Value;
137142
}
143+
144+
public static bool IsValueForced(this Token token)
145+
{
146+
return token.IsValue() && ((Value)token).Forced;
147+
}
148+
149+
public static bool IsValueUnforced(this Token token)
150+
{
151+
return token.IsValue() && ! ((Value)token).Forced;
152+
}
138153
}
139-
}
154+
}

src/CommandLine/Core/Tokenizer.cs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ public static Result<IEnumerable<Token>, Error> Tokenize(
3434
int consumeNext = 0;
3535
Action<int> onConsumeNext = (n => consumeNext = consumeNext + n);
3636

37+
bool isForced = false;
38+
3739
var tokens = new List<Token>();
3840

3941
var enumerator = arguments.GetEnumerator();
@@ -44,21 +46,22 @@ public static Result<IEnumerable<Token>, Error> Tokenize(
4446
break;
4547

4648
case string arg when consumeNext > 0:
47-
tokens.Add(new Value(arg));
49+
tokens.Add(new Value(arg, isForced));
4850
consumeNext = consumeNext - 1;
4951
break;
5052

5153
case "--" when allowDashDash:
5254
consumeNext = System.Int32.MaxValue;
55+
isForced = true;
5356
break;
5457

5558
case "--":
56-
tokens.Add(new Value("--"));
59+
tokens.Add(new Value("--", isForced));
5760
break;
5861

5962
case "-":
6063
// A single hyphen is always a value (it usually means "read from stdin" or "write to stdout")
61-
tokens.Add(new Value("-"));
64+
tokens.Add(new Value("-", isForced));
6265
break;
6366

6467
case string arg when arg.StartsWith("--"):
@@ -71,7 +74,7 @@ public static Result<IEnumerable<Token>, Error> Tokenize(
7174

7275
case string arg:
7376
// If we get this far, it's a plain value
74-
tokens.Add(new Value(arg));
77+
tokens.Add(new Value(arg, isForced));
7578
break;
7679
}
7780
}
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)