diff --git a/src/System.CommandLine.Tests/ArgumentTests.cs b/src/System.CommandLine.Tests/ArgumentTests.cs index 1f4b18aaa1..b48b039d41 100644 --- a/src/System.CommandLine.Tests/ArgumentTests.cs +++ b/src/System.CommandLine.Tests/ArgumentTests.cs @@ -675,7 +675,7 @@ public void OnlyTake_throws_when_called_twice() } [Fact] - public void OnlyTake_can_pass_on_all_tokens() + public void OnlyTake_can_pass_on_all_tokens_from_one_multiple_arity_argument_to_another() { var argument1 = new Argument(result => { @@ -695,6 +695,29 @@ public void OnlyTake_can_pass_on_all_tokens() result.GetValueForArgument(argument2).Should().BeEquivalentSequenceTo(1, 2, 3); } + + [Fact] // https://github.com/dotnet/command-line-api/issues/1759 + public void OnlyTake_can_pass_on_all_tokens_from_a_single_arity_argument_to_another() + { + var scalar = new Argument(parse: ctx => + { + ctx.OnlyTake(0); + return null; + }); + Argument multiple = new(); + + var command = new RootCommand + { + scalar, + multiple + }; + + var result = command.Parse("1 2 3"); + + result.GetValueForArgument(scalar).Should().BeNull(); + + result.GetValueForArgument(multiple).Should().BeEquivalentSequenceTo(1, 2, 3); + } } protected override Symbol CreateSymbol(string name) diff --git a/src/System.CommandLine/Parsing/ArgumentResult.cs b/src/System.CommandLine/Parsing/ArgumentResult.cs index 69e4cb18b2..7323e44e5e 100644 --- a/src/System.CommandLine/Parsing/ArgumentResult.cs +++ b/src/System.CommandLine/Parsing/ArgumentResult.cs @@ -67,7 +67,7 @@ public void OnlyTake(int numberOfTokens) var passedOnTokensCount = _tokens.Count - numberOfTokens; PassedOnTokens = new List(_tokens.GetRange(numberOfTokens, passedOnTokensCount)); - + _tokens.RemoveRange(numberOfTokens, passedOnTokensCount); } @@ -76,11 +76,6 @@ public void OnlyTake(int numberOfTokens) internal ParseError? CustomError(Argument argument) { - if (!string.IsNullOrEmpty(ErrorMessage)) - { - return new ParseError(ErrorMessage!, this); - } - for (var i = 0; i < argument.Validators.Count; i++) { var validateSymbolResult = argument.Validators[i]; @@ -99,11 +94,11 @@ private ArgumentConversionResult Convert(Argument argument) { if (ShouldCheckArity() && Parent is { } && - ArgumentArity.Validate(Parent, + ArgumentArity.Validate( + Parent, argument, argument.Arity.MinimumNumberOfValues, - argument.Arity.MaximumNumberOfValues) is ArgumentConversionResult failed && - failed is not null) // returns null on success + argument.Arity.MaximumNumberOfValues) is { } failed) // returns null on success { return failed; } @@ -138,11 +133,6 @@ Parent is { } && }; } - if (_conversionResult is not null) - { - return _conversionResult; - } - var success = argument.ConvertArguments(this, out var value); if (value is ArgumentConversionResult conversionResult) diff --git a/src/System.CommandLine/Parsing/ParseResultVisitor.cs b/src/System.CommandLine/Parsing/ParseResultVisitor.cs index e7c64a5239..03adfa83d1 100644 --- a/src/System.CommandLine/Parsing/ParseResultVisitor.cs +++ b/src/System.CommandLine/Parsing/ParseResultVisitor.cs @@ -256,6 +256,18 @@ private void ValidateAndConvertArgumentResults(IReadOnlyList arguments { for (var i = 0; i < arguments.Count; i++) { + if (i > 0 && _argumentResults.Count > 1) + { + var previousArgumentResult = _argumentResults[i - 1]; + + var passedOnTokensCount = previousArgumentResult.PassedOnTokens?.Count; + + if (passedOnTokensCount > 0) + { + ShiftPassedOnTokensToNextResult(previousArgumentResult, _argumentResults[i], passedOnTokensCount); + } + } + // If this is the current last result but there are more arguments, see if we can shift tokens to the next argument if (commandArgumentResultCount == i) { @@ -268,18 +280,7 @@ private void ValidateAndConvertArgumentResults(IReadOnlyList arguments var passedOnTokensCount = _innermostCommandResult?.Tokens.Count; - for (var j = previousArgumentResult.Tokens.Count; j < passedOnTokensCount; j++) - { - if (nextArgumentResult.IsArgumentLimitReached) - { - break; - } - - if (_innermostCommandResult is not null) - { - nextArgumentResult.AddToken(_innermostCommandResult.Tokens[j]); - } - } + ShiftPassedOnTokensToNextResult(previousArgumentResult, nextArgumentResult, passedOnTokensCount); _argumentResults.Add(nextArgumentResult); @@ -318,6 +319,25 @@ private void ValidateAndConvertArgumentResults(IReadOnlyList arguments } } } + + void ShiftPassedOnTokensToNextResult( + ArgumentResult previous, + ArgumentResult next, + int? numberOfTokens) + { + for (var j = previous.Tokens.Count; j < numberOfTokens; j++) + { + if (next.IsArgumentLimitReached) + { + break; + } + + if (_innermostCommandResult is not null) + { + next.AddToken(_innermostCommandResult.Tokens[j]); + } + } + } } private void ValidateCommandResult() @@ -487,9 +507,10 @@ private void ValidateAndConvertArgumentResult(ArgumentResult argumentResult) return; } - ArgumentConversionResult argumentConversionResult = argumentResult.GetArgumentConversionResult(); - if (argumentConversionResult.Result >= ArgumentConversionResultType.Failed - && argumentConversionResult.Result != ArgumentConversionResultType.FailedArity) + var argumentConversionResult = argumentResult.GetArgumentConversionResult(); + + if (argumentConversionResult.Result >= ArgumentConversionResultType.Failed && + argumentConversionResult.Result != ArgumentConversionResultType.FailedArity) { if (argument.FirstParent?.Symbol is Option option) { @@ -510,19 +531,19 @@ private void ValidateAndConvertArgumentResult(ArgumentResult argumentResult) private void PopulateDefaultValues() { - CommandResult? commandResult = _innermostCommandResult; + var commandResult = _innermostCommandResult; while (commandResult is { }) { - IReadOnlyList