Skip to content

Commit 34ab560

Browse files
committed
Revert "Address review comments"
This reverts commit b7102d8.
1 parent b7102d8 commit 34ab560

File tree

6 files changed

+76
-83
lines changed

6 files changed

+76
-83
lines changed

src/CommandLine/Core/GetoptTokenizer.cs

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,36 @@ public static Result<IEnumerable<Token>, Error> Tokenize(
8888
return Result.Succeed<IEnumerable<Token>, Error>(tokens.AsEnumerable(), errors.AsEnumerable());
8989
}
9090

91+
public static Result<IEnumerable<Token>, Error> ExplodeOptionList(
92+
Result<IEnumerable<Token>, Error> tokenizerResult,
93+
Func<string, Maybe<char>> optionSequenceWithSeparatorLookup)
94+
{
95+
var tokens = tokenizerResult.SucceededWith().Memoize();
96+
97+
var exploded = new List<Token>(tokens is ICollection<Token> coll ? coll.Count : tokens.Count());
98+
var nothing = Maybe.Nothing<char>(); // Re-use same Nothing instance for efficiency
99+
var separator = nothing;
100+
foreach (var token in tokens) {
101+
if (token.IsName()) {
102+
separator = optionSequenceWithSeparatorLookup(token.Text);
103+
exploded.Add(token);
104+
} else {
105+
// Forced values are never considered option values, so they should not be split
106+
if (separator.MatchJust(out char sep) && sep != '\0' && !token.IsValueForced()) {
107+
if (token.Text.Contains(sep)) {
108+
exploded.AddRange(token.Text.Split(sep).Select(Token.ValueFromSeparator));
109+
} else {
110+
exploded.Add(token);
111+
}
112+
} else {
113+
exploded.Add(token);
114+
}
115+
separator = nothing; // Only first value after a separator can possibly be split
116+
}
117+
}
118+
return Result.Succeed(exploded as IEnumerable<Token>, tokenizerResult.SuccessMessages());
119+
}
120+
91121
public static Func<
92122
IEnumerable<string>,
93123
IEnumerable<OptionSpecification>,
@@ -101,7 +131,7 @@ public static Func<
101131
return (arguments, optionSpecs) =>
102132
{
103133
var tokens = GetoptTokenizer.Tokenize(arguments, name => NameLookup.Contains(name, optionSpecs, nameComparer), ignoreUnknownArguments, enableDashDash, posixlyCorrect);
104-
var explodedTokens = Tokenizer.ExplodeOptionList(tokens, name => NameLookup.HavingSeparator(name, optionSpecs, nameComparer));
134+
var explodedTokens = GetoptTokenizer.ExplodeOptionList(tokens, name => NameLookup.HavingSeparator(name, optionSpecs, nameComparer));
105135
return explodedTokens;
106136
};
107137
}

src/CommandLine/Parser.cs

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -185,28 +185,16 @@ private static Result<IEnumerable<Token>, Error> Tokenize(
185185
IEnumerable<OptionSpecification> optionSpecs,
186186
ParserSettings settings)
187187
{
188-
switch (settings.ParserMode)
189-
{
190-
case ParserMode.Legacy:
191-
return Tokenizer.ConfigureTokenizer(
192-
settings.NameComparer,
193-
settings.IgnoreUnknownArguments,
194-
settings.EnableDashDash)(arguments, optionSpecs);
195-
196-
case ParserMode.Getopt:
197-
return GetoptTokenizer.ConfigureTokenizer(
188+
return settings.GetoptMode
189+
? GetoptTokenizer.ConfigureTokenizer(
198190
settings.NameComparer,
199191
settings.IgnoreUnknownArguments,
200192
settings.EnableDashDash,
201-
settings.PosixlyCorrect)(arguments, optionSpecs);
202-
203-
// No need to test ParserMode.Default, as it should always be one of the above modes
204-
default:
205-
return Tokenizer.ConfigureTokenizer(
193+
settings.PosixlyCorrect)(arguments, optionSpecs)
194+
: Tokenizer.ConfigureTokenizer(
206195
settings.NameComparer,
207196
settings.IgnoreUnknownArguments,
208197
settings.EnableDashDash)(arguments, optionSpecs);
209-
}
210198
}
211199

212200
private static ParserResult<T> MakeParserResult<T>(ParserResult<T> parserResult, ParserSettings settings)

src/CommandLine/ParserSettings.cs

Lines changed: 10 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,6 @@
99

1010
namespace CommandLine
1111
{
12-
public enum ParserMode
13-
{
14-
Legacy,
15-
Getopt,
16-
17-
Default = Legacy
18-
}
19-
2012
/// <summary>
2113
/// Provides settings for <see cref="CommandLine.Parser"/>. Once consumed cannot be reused.
2214
/// </summary>
@@ -35,7 +27,7 @@ public class ParserSettings : IDisposable
3527
private Maybe<bool> enableDashDash;
3628
private int maximumDisplayWidth;
3729
private Maybe<bool> allowMultiInstance;
38-
private ParserMode parserMode;
30+
private bool getoptMode;
3931
private Maybe<bool> posixlyCorrect;
4032

4133
/// <summary>
@@ -49,7 +41,7 @@ public ParserSettings()
4941
autoVersion = true;
5042
parsingCulture = CultureInfo.InvariantCulture;
5143
maximumDisplayWidth = GetWindowWidth();
52-
parserMode = ParserMode.Default;
44+
getoptMode = false;
5345
enableDashDash = Maybe.Nothing<bool>();
5446
allowMultiInstance = Maybe.Nothing<bool>();
5547
posixlyCorrect = Maybe.Nothing<bool>();
@@ -174,11 +166,11 @@ public bool AutoVersion
174166
/// <summary>
175167
/// Gets or sets a value indicating whether enable double dash '--' syntax,
176168
/// that forces parsing of all subsequent tokens as values.
177-
/// Normally defaults to false. If ParserMode = ParserMode.Getopt, this defaults to true, but can be turned off by explicitly specifying EnableDashDash = false.
169+
/// If GetoptMode is true, this defaults to true, but can be turned off by explicitly specifying EnableDashDash = false.
178170
/// </summary>
179171
public bool EnableDashDash
180172
{
181-
get => enableDashDash.MatchJust(out bool value) ? value : (parserMode == ParserMode.Getopt);
173+
get => enableDashDash.MatchJust(out bool value) ? value : getoptMode;
182174
set => PopsicleSetter.Set(Consumed, ref enableDashDash, Maybe.Just(value));
183175
}
184176

@@ -193,38 +185,21 @@ public int MaximumDisplayWidth
193185

194186
/// <summary>
195187
/// Gets or sets a value indicating whether options are allowed to be specified multiple times.
196-
/// If ParserMode = ParserMode.Getopt, this defaults to true, but can be turned off by explicitly specifying AllowMultiInstance = false.
188+
/// If GetoptMode is true, this defaults to true, but can be turned off by explicitly specifying AllowMultiInstance = false.
197189
/// </summary>
198190
public bool AllowMultiInstance
199191
{
200-
get => allowMultiInstance.MatchJust(out bool value) ? value : (parserMode == ParserMode.Getopt);
192+
get => allowMultiInstance.MatchJust(out bool value) ? value : getoptMode;
201193
set => PopsicleSetter.Set(Consumed, ref allowMultiInstance, Maybe.Just(value));
202194
}
203195

204196
/// <summary>
205-
/// Set this to change how the parser processes command-line arguments. Currently valid values are:
206-
/// <list>
207-
/// <item>
208-
/// <term>Legacy</term>
209-
/// <description>Uses - for short options and -- for long options.
210-
/// Values of long options can only start with a - character if the = syntax is used.
211-
/// E.g., "--string-option -x" will consider "-x" to be an option, not the value of "--string-option",
212-
/// but "--string-option=-x" will consider "-x" to be the value of "--string-option".</description>
213-
/// </item>
214-
/// <item>
215-
/// <term>Getopt</term>
216-
/// <description>Strict getopt-like processing is applied to option values.
217-
/// Mostly like legacy mode, except that option values with = and with space are more consistent.
218-
/// After an option that takes a value, and whose value was not specified with "=", the next argument will be considered the value even if it starts with "-".
219-
/// E.g., both "--string-option=-x" and "--string-option -x" will consider "-x" to be the value of "--string-option".
220-
/// If this mode is chosen, AllowMultiInstance and EnableDashDash will default to true as well, though they can be explicitly turned off if desired.</description>
221-
/// </item>
222-
/// </list>
197+
/// Whether strict getopt-like processing is applied to option values; if true, AllowMultiInstance and EnableDashDash will default to true as well.
223198
/// </summary>
224-
public ParserMode ParserMode
199+
public bool GetoptMode
225200
{
226-
get => parserMode;
227-
set => PopsicleSetter.Set(Consumed, ref parserMode, value);
201+
get => getoptMode;
202+
set => PopsicleSetter.Set(Consumed, ref getoptMode, value);
228203
}
229204

230205
/// <summary>

tests/CommandLine.Tests/Unit/Core/GetoptTokenizerTests.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public void Explode_scalar_with_separator_in_odd_args_input_returns_sequence()
2424

2525
// Exercize system
2626
var result =
27-
Tokenizer.ExplodeOptionList(
27+
GetoptTokenizer.ExplodeOptionList(
2828
Result.Succeed(
2929
Enumerable.Empty<Token>().Concat(new[] { Token.Name("i"), Token.Value("10"),
3030
Token.Name("string-seq"), Token.Value("aaa,bb,cccc"), Token.Name("switch") }),
@@ -47,7 +47,7 @@ public void Explode_scalar_with_separator_in_even_args_input_returns_sequence()
4747

4848
// Exercize system
4949
var result =
50-
Tokenizer.ExplodeOptionList(
50+
GetoptTokenizer.ExplodeOptionList(
5151
Result.Succeed(
5252
Enumerable.Empty<Token>().Concat(new[] { Token.Name("x"),
5353
Token.Name("string-seq"), Token.Value("aaa,bb,cccc"), Token.Name("switch") }),
@@ -90,7 +90,7 @@ public void Should_return_error_if_option_format_with_equals_is_not_correct()
9090
var errors = result.SuccessMessages();
9191

9292
Assert.NotNull(errors);
93-
Assert.NotEmpty(errors);
93+
Assert.Equal(1, errors.Count());
9494
Assert.Equal(ErrorType.BadFormatTokenError, errors.First().Tag);
9595

9696
var tokens = result.SucceededWith();

tests/CommandLine.Tests/Unit/GetoptParserTests.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ public void Getopt_parser_without_posixly_correct_allows_mixed_options_and_nonop
155155
{
156156
// Arrange
157157
var sut = new Parser(config => {
158-
config.ParserMode = ParserMode.Getopt;
158+
config.GetoptMode = true;
159159
config.PosixlyCorrect = false;
160160
});
161161

@@ -215,7 +215,7 @@ public void Getopt_parser_with_posixly_correct_stops_parsing_at_first_nonoption(
215215
{
216216
// Arrange
217217
var sut = new Parser(config => {
218-
config.ParserMode = ParserMode.Getopt;
218+
config.GetoptMode = true;
219219
config.PosixlyCorrect = true;
220220
config.EnableDashDash = true;
221221
});
@@ -233,7 +233,7 @@ public void Getopt_mode_defaults_to_EnableDashDash_being_true()
233233
{
234234
// Arrange
235235
var sut = new Parser(config => {
236-
config.ParserMode = ParserMode.Getopt;
236+
config.GetoptMode = true;
237237
config.PosixlyCorrect = false;
238238
});
239239
var args = new string [] {"--stringvalue", "foo", "256", "--", "-x", "-sbar" };
@@ -259,7 +259,7 @@ public void Getopt_mode_can_have_EnableDashDash_expicitly_disabled()
259259
{
260260
// Arrange
261261
var sut = new Parser(config => {
262-
config.ParserMode = ParserMode.Getopt;
262+
config.GetoptMode = true;
263263
config.PosixlyCorrect = false;
264264
config.EnableDashDash = false;
265265
});

tests/CommandLine.Tests/Unit/SequenceParsingTests.cs

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -17,31 +17,31 @@ public class SequenceParsingTests
1717
{
1818
// Issue #91
1919
[Theory]
20-
[InlineData(ParserMode.Legacy)]
21-
[InlineData(ParserMode.Getopt)]
22-
public static void Enumerable_with_separator_before_values_does_not_try_to_parse_too_much(ParserMode parserMode)
20+
[InlineData(false)]
21+
[InlineData(true)]
22+
public static void Enumerable_with_separator_before_values_does_not_try_to_parse_too_much(bool useGetoptMode)
2323
{
2424
var args = "--exclude=a,b InputFile.txt".Split();
2525
var expected = new Options_For_Issue_91 {
2626
Excluded = new[] { "a", "b" },
2727
Included = Enumerable.Empty<string>(),
2828
InputFileName = "InputFile.txt",
2929
};
30-
var sut = new Parser(parserSettings => { parserSettings.ParserMode = parserMode; });
30+
var sut = new Parser(parserSettings => { parserSettings.GetoptMode = useGetoptMode; });
3131
var result = sut.ParseArguments<Options_For_Issue_91>(args);
3232
result.Should().BeOfType<Parsed<Options_For_Issue_91>>();
3333
result.As<Parsed<Options_For_Issue_91>>().Value.Should().BeEquivalentTo(expected);
3434
}
3535

3636
// Issue #396
3737
[Theory]
38-
[InlineData(ParserMode.Legacy)]
39-
[InlineData(ParserMode.Getopt)]
40-
public static void Options_with_similar_names_are_not_ambiguous(ParserMode parserMode)
38+
[InlineData(false)]
39+
[InlineData(true)]
40+
public static void Options_with_similar_names_are_not_ambiguous(bool useGetoptMode)
4141
{
4242
var args = new[] { "--configure-profile", "deploy", "--profile", "local" };
4343
var expected = new Options_With_Similar_Names { ConfigureProfile = "deploy", Profile = "local", Deploys = Enumerable.Empty<string>() };
44-
var sut = new Parser(parserSettings => { parserSettings.ParserMode = parserMode; });
44+
var sut = new Parser(parserSettings => { parserSettings.GetoptMode = useGetoptMode; });
4545
var result = sut.ParseArguments<Options_With_Similar_Names>(args);
4646
result.Should().BeOfType<Parsed<Options_With_Similar_Names>>();
4747
result.As<Parsed<Options_With_Similar_Names>>().Value.Should().BeEquivalentTo(expected);
@@ -68,61 +68,61 @@ public static void Values_with_same_name_as_sequence_option_do_not_cause_later_v
6868

6969
// Issue #454
7070
[Theory]
71-
[InlineData(ParserMode.Legacy)]
72-
[InlineData(ParserMode.Getopt)]
71+
[InlineData(false)]
72+
[InlineData(true)]
7373

74-
public static void Enumerable_with_colon_separator_before_values_does_not_try_to_parse_too_much(ParserMode parserMode)
74+
public static void Enumerable_with_colon_separator_before_values_does_not_try_to_parse_too_much(bool useGetoptMode)
7575
{
7676
var args = "-c chanA:chanB file.hdf5".Split();
7777
var expected = new Options_For_Issue_454 {
7878
Channels = new[] { "chanA", "chanB" },
7979
ArchivePath = "file.hdf5",
8080
};
81-
var sut = new Parser(parserSettings => { parserSettings.ParserMode = parserMode; });
81+
var sut = new Parser(parserSettings => { parserSettings.GetoptMode = useGetoptMode; });
8282
var result = sut.ParseArguments<Options_For_Issue_454>(args);
8383
result.Should().BeOfType<Parsed<Options_For_Issue_454>>();
8484
result.As<Parsed<Options_For_Issue_454>>().Value.Should().BeEquivalentTo(expected);
8585
}
8686

8787
// Issue #510
8888
[Theory]
89-
[InlineData(ParserMode.Legacy)]
90-
[InlineData(ParserMode.Getopt)]
89+
[InlineData(false)]
90+
[InlineData(true)]
9191

92-
public static void Enumerable_before_values_does_not_try_to_parse_too_much(ParserMode parserMode)
92+
public static void Enumerable_before_values_does_not_try_to_parse_too_much(bool useGetoptMode)
9393
{
9494
var args = new[] { "-a", "1,2", "c" };
9595
var expected = new Options_For_Issue_510 { A = new[] { "1", "2" }, C = "c" };
96-
var sut = new Parser(parserSettings => { parserSettings.ParserMode = parserMode; });
96+
var sut = new Parser(parserSettings => { parserSettings.GetoptMode = useGetoptMode; });
9797
var result = sut.ParseArguments<Options_For_Issue_510>(args);
9898
result.Should().BeOfType<Parsed<Options_For_Issue_510>>();
9999
result.As<Parsed<Options_For_Issue_510>>().Value.Should().BeEquivalentTo(expected);
100100
}
101101

102102
// Issue #617
103103
[Theory]
104-
[InlineData(ParserMode.Legacy)]
105-
[InlineData(ParserMode.Getopt)]
104+
[InlineData(false)]
105+
[InlineData(true)]
106106

107-
public static void Enumerable_with_enum_before_values_does_not_try_to_parse_too_much(ParserMode parserMode)
107+
public static void Enumerable_with_enum_before_values_does_not_try_to_parse_too_much(bool useGetoptMode)
108108
{
109109
var args = "--fm D,C a.txt".Split();
110110
var expected = new Options_For_Issue_617 {
111111
Mode = new[] { FMode.D, FMode.C },
112112
Files = new[] { "a.txt" },
113113
};
114-
var sut = new Parser(parserSettings => { parserSettings.ParserMode = parserMode; });
114+
var sut = new Parser(parserSettings => { parserSettings.GetoptMode = useGetoptMode; });
115115
var result = sut.ParseArguments<Options_For_Issue_617>(args);
116116
result.Should().BeOfType<Parsed<Options_For_Issue_617>>();
117117
result.As<Parsed<Options_For_Issue_617>>().Value.Should().BeEquivalentTo(expected);
118118
}
119119

120120
// Issue #619
121121
[Theory]
122-
[InlineData(ParserMode.Legacy)]
123-
[InlineData(ParserMode.Getopt)]
122+
[InlineData(false)]
123+
[InlineData(true)]
124124

125-
public static void Separator_just_before_values_does_not_try_to_parse_values(ParserMode parserMode)
125+
public static void Separator_just_before_values_does_not_try_to_parse_values(bool useGetoptMode)
126126
{
127127
var args = "--outdir ./x64/Debug --modules ../utilities/x64/Debug,../auxtool/x64/Debug m_xfunit.f03 m_xfunit_assertion.f03".Split();
128128
var expected = new Options_For_Issue_619 {
@@ -131,7 +131,7 @@ public static void Separator_just_before_values_does_not_try_to_parse_values(Par
131131
Ignores = Enumerable.Empty<string>(),
132132
Srcs = new[] { "m_xfunit.f03", "m_xfunit_assertion.f03" },
133133
};
134-
var sut = new Parser(parserSettings => { parserSettings.ParserMode = parserMode; });
134+
var sut = new Parser(parserSettings => { parserSettings.GetoptMode = useGetoptMode; });
135135
var result = sut.ParseArguments<Options_For_Issue_619>(args);
136136
result.Should().BeOfType<Parsed<Options_For_Issue_619>>();
137137
result.As<Parsed<Options_For_Issue_619>>().Value.Should().BeEquivalentTo(expected);

0 commit comments

Comments
 (0)