Add support for space-separated command names in input parser

This enables multi-level subcommands
Closes #2
This commit is contained in:
Alexey Golub
2019-07-26 00:00:26 +03:00
parent a64a8fc651
commit 5ac9b33056
5 changed files with 26 additions and 11 deletions

View File

@@ -22,7 +22,7 @@ namespace CliFx.Tests
public Task ExecuteAsync(CommandContext context) => Task.CompletedTask; public Task ExecuteAsync(CommandContext context) => Task.CompletedTask;
} }
[Command("faulty-command")] [Command("faulty command")]
private class TestFaultyCommand : ICommand private class TestFaultyCommand : ICommand
{ {
public Task ExecuteAsync(CommandContext context) => Task.FromException(new CommandErrorException(-1337)); public Task ExecuteAsync(CommandContext context) => Task.FromException(new CommandErrorException(-1337));
@@ -115,17 +115,17 @@ namespace CliFx.Tests
yield return new TestCaseData( yield return new TestCaseData(
new[] {typeof(TestFaultyCommand)}, new[] {typeof(TestFaultyCommand)},
new[] {"faulty-command", "--help"} new[] {"faulty", "command", "--help"}
); );
yield return new TestCaseData( yield return new TestCaseData(
new[] {typeof(TestFaultyCommand)}, new[] {typeof(TestFaultyCommand)},
new[] {"faulty-command", "-h"} new[] {"faulty", "command", "-h"}
); );
yield return new TestCaseData( yield return new TestCaseData(
new[] {typeof(TestFaultyCommand)}, new[] {typeof(TestFaultyCommand)},
new[] {"faulty-command", "-?"} new[] {"faulty", "command", "-?"}
); );
} }
@@ -165,7 +165,7 @@ namespace CliFx.Tests
yield return new TestCaseData( yield return new TestCaseData(
new Type[0], new Type[0],
new[] {"faulty-command"} new[] {"faulty", "command"}
); );
// Specified command is not defined // Specified command is not defined
@@ -194,7 +194,7 @@ namespace CliFx.Tests
yield return new TestCaseData( yield return new TestCaseData(
new[] {typeof(TestFaultyCommand)}, new[] {typeof(TestFaultyCommand)},
new[] {"faulty-command"} new[] {"faulty", "command"}
); );
} }

View File

@@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using CliFx.Attributes;
using CliFx.Models; using CliFx.Models;
using CliFx.Services; using CliFx.Services;
using NUnit.Framework; using NUnit.Framework;
@@ -9,6 +10,7 @@ namespace CliFx.Tests
{ {
public partial class CommandFactoryTests public partial class CommandFactoryTests
{ {
[Command]
private class TestCommand : ICommand private class TestCommand : ICommand
{ {
public Task ExecuteAsync(CommandContext context) => throw new NotImplementedException(); public Task ExecuteAsync(CommandContext context) => throw new NotImplementedException();

View File

@@ -11,6 +11,7 @@ namespace CliFx.Tests
{ {
public partial class CommandInitializerTests public partial class CommandInitializerTests
{ {
[Command]
public class TestCommand : ICommand public class TestCommand : ICommand
{ {
[CommandOption("int", 'i', IsRequired = true)] [CommandOption("int", 'i', IsRequired = true)]

View File

@@ -151,6 +151,11 @@ namespace CliFx.Tests
new CommandOptionInput("option", "value") new CommandOptionInput("option", "value")
}) })
); );
yield return new TestCaseData(
new[] {"long", "command", "name"},
new CommandInput("long command name")
);
} }
[Test] [Test]

View File

@@ -21,7 +21,7 @@ namespace CliFx.Services
string optionName = null; string optionName = null;
// Loop through all arguments // Loop through all arguments
var isFirstArgument = true; var encounteredFirstOption = false;
foreach (var commandLineArgument in commandLineArguments) foreach (var commandLineArgument in commandLineArguments)
{ {
// Option name // Option name
@@ -32,6 +32,8 @@ namespace CliFx.Services
if (rawOptions.GetValueOrDefault(optionName) == null) if (rawOptions.GetValueOrDefault(optionName) == null)
rawOptions[optionName] = new List<string>(); rawOptions[optionName] = new List<string>();
encounteredFirstOption = true;
} }
// Short option name // Short option name
@@ -42,6 +44,8 @@ namespace CliFx.Services
if (rawOptions.GetValueOrDefault(optionName) == null) if (rawOptions.GetValueOrDefault(optionName) == null)
rawOptions[optionName] = new List<string>(); rawOptions[optionName] = new List<string>();
encounteredFirstOption = true;
} }
// Multiple stacked short options // Multiple stacked short options
@@ -54,12 +58,17 @@ namespace CliFx.Services
if (rawOptions.GetValueOrDefault(optionName) == null) if (rawOptions.GetValueOrDefault(optionName) == null)
rawOptions[optionName] = new List<string>(); rawOptions[optionName] = new List<string>();
} }
encounteredFirstOption = true;
} }
// Command name // Command name
else if (isFirstArgument) else if (!encounteredFirstOption)
{ {
commandName = commandLineArgument; if (commandName.IsNullOrWhiteSpace())
commandName = commandLineArgument;
else
commandName += " " + commandLineArgument;
} }
// Option value // Option value
@@ -68,8 +77,6 @@ namespace CliFx.Services
// ReSharper disable once AssignNullToNotNullAttribute // ReSharper disable once AssignNullToNotNullAttribute
rawOptions[optionName].Add(commandLineArgument); rawOptions[optionName].Add(commandLineArgument);
} }
isFirstArgument = false;
} }
return new CommandInput(commandName, rawOptions.Select(p => new CommandOptionInput(p.Key, p.Value)).ToArray()); return new CommandInput(commandName, rawOptions.Select(p => new CommandOptionInput(p.Key, p.Value)).ToArray());