diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index 16823bf2..febcc4c7 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -1,4 +1,4 @@
-### 3.0.0-alpha009
+### 3.0.0-alpha010
* Add subcommand support.
* Add support for list and option parameters.
* Add support for grouped switches.
diff --git a/src/Argu/ParseResult.fs b/src/Argu/ParseResult.fs
index 7fd26c5b..38cdd433 100644
--- a/src/Argu/ParseResult.fs
+++ b/src/Argu/ParseResult.fs
@@ -54,6 +54,10 @@ type ParseResult<'Template when 'Template :> IArgParserTemplate>
/// accumulates if parsed with 'ignoreUnrecognized = true'
member __.UnrecognizedCliParams = results.UnrecognizedCliParams
+ /// Gets all parse results that are not part of the current parsing context
+ /// This is only applicable to subcommand parsing operations
+ member __.UnrecognizedCliParseResults = results.UnrecognizedCliParseResults
+
/// Query parse results for parameterless argument.
/// The name of the parameter, expressed as quotation of DU constructor.
/// Optional source restriction: AppSettings or CommandLine.
diff --git a/src/Argu/Parsers/Cli.fs b/src/Argu/Parsers/Cli.fs
index 0b338ac8..3149ca30 100644
--- a/src/Argu/Parsers/Cli.fs
+++ b/src/Argu/Parsers/Cli.fs
@@ -58,6 +58,7 @@ type CliParseResultAggregator internal (argInfo : UnionArgInfo, stack : CliParse
let mutable resultCount = 0
let mutable isSubCommandDefined = false
let unrecognized = new ResizeArray()
+ let unrecognizedParseResults = new ResizeArray()
let results = argInfo.Cases |> Array.map (fun _ -> new ResizeArray ())
member val IsUsageRequested = false with get,set
@@ -65,8 +66,7 @@ type CliParseResultAggregator internal (argInfo : UnionArgInfo, stack : CliParse
member __.IsSubCommandDefined = isSubCommandDefined
member __.AppendResult(result : UnionCaseParseResult) =
- match result.CaseInfo.Depth with
- | d when argInfo.Depth = d ->
+ if result.CaseInfo.Depth = argInfo.Depth then
resultCount <- resultCount + 1
let agg = results.[result.Tag]
if result.CaseInfo.IsUnique && agg.Count > 0 then
@@ -76,30 +76,36 @@ type CliParseResultAggregator internal (argInfo : UnionArgInfo, stack : CliParse
isSubCommandDefined <- true
agg.Add result
-
- | d ->
+ else
// this parse result corresponds to an inherited parameter
// from a parent syntax. Use the ResultAggregator stack to
// re-route the result to its matching aggregator
- stack.[d].AppendResult result
+ if stack.TryDispatchResult result then ()
+ else unrecognizedParseResults.Add result.Value
member __.AppendUnrecognized(token:string) = unrecognized.Add token
member __.ToUnionParseResults() =
{ Cases = results |> Array.map (fun c -> c.ToArray()) ;
UnrecognizedCliParams = Seq.toList unrecognized ;
+ UnrecognizedCliParseResults = Seq.toList unrecognizedParseResults ;
IsUsageRequested = __.IsUsageRequested }
// this rudimentary stack implementation assumes that only one subcommand
// can occur within any particular context; no need implement popping etc.
// Note that inheritting subcommands is explicitly prohibited by the library.
-and CliParseResultAggregatorStack () =
- let stack = new ResizeArray(capacity = 5)
+and CliParseResultAggregatorStack (context : UnionArgInfo) =
+ let offset = context.Depth
+ let stack = new ResizeArray(capacity = 2)
- member __.Item (depth : int) : CliParseResultAggregator = stack.[depth]
+ member self.TryDispatchResult(result : UnionCaseParseResult) =
+ if result.CaseInfo.Depth < offset then false
+ else
+ stack.[result.CaseInfo.Depth - offset].AppendResult result
+ true
member self.CreateNextAggregator(argInfo : UnionArgInfo) =
- assert(stack.Count = argInfo.Depth)
+ assert(stack.Count = argInfo.Depth - offset)
let agg = new CliParseResultAggregator(argInfo, self)
stack.Add agg
agg
@@ -281,7 +287,7 @@ and parseCommandLine (argInfo : UnionArgInfo) (programName : string) (descriptio
let state = {
Reader = new CliTokenReader(inputs)
ProgramName = programName
- ResultStack = new CliParseResultAggregatorStack()
+ ResultStack = new CliParseResultAggregatorStack(argInfo)
Description = description
UsageStringCharWidth = width
RaiseOnUsage = raiseOnUsage
diff --git a/src/Argu/Parsers/Common.fs b/src/Argu/Parsers/Common.fs
index d3e783b9..56d3c61d 100644
--- a/src/Argu/Parsers/Common.fs
+++ b/src/Argu/Parsers/Common.fs
@@ -42,6 +42,7 @@ let mkParseResultFromValues (info : UnionArgInfo) (exiter : IExiter) (width : in
{
IsUsageRequested = false
UnrecognizedCliParams = []
+ UnrecognizedCliParseResults = []
Cases = agg |> Array.map (fun rs -> rs.ToArray())
}
@@ -76,5 +77,6 @@ let postProcessResults (argInfo : UnionArgInfo) (ignoreMissingMandatory : bool)
{
Cases = argInfo.Cases |> Array.map combineSingle
UnrecognizedCliParams = match commandLineResults with Some clr -> clr.UnrecognizedCliParams | None -> []
+ UnrecognizedCliParseResults = match commandLineResults with Some clr -> clr.UnrecognizedCliParseResults | None -> []
IsUsageRequested = commandLineResults |> Option.exists (fun r -> r.IsUsageRequested)
}
\ No newline at end of file
diff --git a/src/Argu/UnionArgInfo.fs b/src/Argu/UnionArgInfo.fs
index 604470fe..73b306a4 100644
--- a/src/Argu/UnionArgInfo.fs
+++ b/src/Argu/UnionArgInfo.fs
@@ -183,6 +183,8 @@ type UnionParseResults =
Cases : UnionCaseParseResult[][]
/// CLI tokens not recognized by the parser
UnrecognizedCliParams : string list
+ /// CLI parse objects not belonging to the current parser context
+ UnrecognizedCliParseResults : obj list
/// Usage string requested by the caller
IsUsageRequested : bool
}
diff --git a/tests/Argu.Tests/Tests.fs b/tests/Argu.Tests/Tests.fs
index c834c9a5..628b2df0 100644
--- a/tests/Argu.Tests/Tests.fs
+++ b/tests/Argu.Tests/Tests.fs
@@ -268,6 +268,12 @@ module ``Argu Tests`` =
test <@ match results.TryGetSubCommand() with Some (Clean _) -> true | _ -> false @>
test <@ nested.GetAllResults() = [F; D; X] @>
+ []
+ let ``SubParsers should correctly handle inherited params`` () =
+ let subParser = parser.GetSubCommandParser <@ Clean @>
+ let result = subParser.ParseCommandLine [|"-fdxv"|]
+ test <@ match result.UnrecognizedCliParseResults with [:? Argument as c ] -> c = Verbose | _ -> false @>
+
[]
let ``Doubly nested subcommand parsing`` () =
let args = [|"required" ; "--foo" ; "sub" ; "-fdx" |]