internal static OptionResult CreateImplicit( IOption option, CommandResult parent) { var result = new OptionResult(option, option.DefaultToken()); result.IsImplicit = true; if (option.Argument.HasDefaultValue) { var value = option.Argument.GetDefaultValue(); switch (value) { case string arg: result.TryTakeToken(new Token(arg, TokenType.Argument)); break; default: result.ArgumentResult = ArgumentResult.Success(value); break; } } return(result); }
public void Custom_types_and_conversion_logic_can_be_specified() { var argument = new Argument <MyCustomType>(parsed => { var custom = new MyCustomType(); foreach (var a in parsed.Arguments) { custom.Add(a); } return(ArgumentResult.Success(custom)); }) { Arity = ArgumentArity.ZeroOrMore }; var parser = new Parser( new Command("custom", "", argument: argument)); var result = parser.Parse("custom one two three"); var customType = result.CommandResult.GetValueOrDefault <MyCustomType>(); customType .Values .Should() .BeEquivalentTo("one", "two", "three"); }
private static void AddSourceFileOption(Command csharp) { var sourceFileArg = new Argument <RelativeFilePath>( result => { var filename = result.Tokens.Select(t => t.Value).SingleOrDefault(); if (filename == null) { return(ArgumentResult.Success(null)); } if (RelativeFilePath.TryParse(filename, out var relativeFilePath)) { return(ArgumentResult.Success(relativeFilePath)); } return(ArgumentResult.Failure($"Error parsing the filename: {filename}")); }) { Name = "SourceFile", Arity = ArgumentArity.ZeroOrOne }; var sourceFileOption = new Option("--source-file", argument: sourceFileArg); csharp.AddOption(sourceFileOption); }
private static void AddProjectOption( Command csharp, IDirectoryAccessor directoryAccessor) { var projectOptionArgument = new Argument <FileInfo>(result => { var projectPath = new RelativeFilePath(result.Tokens.Select(t => t.Value).Single()); if (directoryAccessor.FileExists(projectPath)) { return(ArgumentResult.Success(directoryAccessor.GetFullyQualifiedPath(projectPath))); } return(ArgumentResult.Failure($"Project not found: {projectPath.Value}")); }) { Name = "project", Arity = ArgumentArity.ExactlyOne }; projectOptionArgument.SetDefaultValue(() => { var rootDirectory = directoryAccessor.GetFullyQualifiedPath(new RelativeDirectoryPath(".")); var projectFiles = directoryAccessor.GetAllFilesRecursively() .Where(file => { return(directoryAccessor.GetFullyQualifiedPath(file.Directory).FullName == rootDirectory.FullName && file.Extension == ".csproj"); }) .ToArray(); if (projectFiles.Length == 1) { return(directoryAccessor.GetFullyQualifiedPath(projectFiles.Single())); } return(null); }); var projectOption = new Option("--project", argument: projectOptionArgument); csharp.Add(projectOption); }
public void Argument_defaults_arity_to_One_for_non_IEnumerable_types() { var argument = new Argument <int>(s => ArgumentResult.Success(1)); argument.Arity.Should().BeEquivalentTo(ArgumentArity.ExactlyOne); }
public static Task <int> Main(string[] args) { #if !NOCODEPAGES Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); #endif // !NOCODEPAGES var cliParser = new CommandLineBuilder(RootCommand()) .UseDefaults() .UseMiddleware(async(invokeCtx, next) => { var cts = new CancellationTokenSource(); var onCancelKeyPress = new ConsoleCancelEventHandler((object senter, ConsoleCancelEventArgs e) => { // If cancellation already has been requested, // do not cancel process termination signal. e.Cancel = !cts.IsCancellationRequested; cts.Cancel(throwOnFirstException: true); }); Console.CancelKeyPress += onCancelKeyPress; invokeCtx.BindingContext.AddService(typeof(CancellationTokenSource), () => cts); invokeCtx.BindingContext.AddService(typeof(CancellationToken), () => cts.Token); try { await next(invokeCtx).ConfigureAwait(false); } catch (OperationCanceledException) { } finally { Console.CancelKeyPress -= onCancelKeyPress; } }) .Build(); return(cliParser.InvokeAsync(args ?? Array.Empty <string>())); RootCommand RootCommand() { var root = new RootCommand(description); root.AddOption(new Option( new string[] { "-d", "--decode" }, "decode data (encodes by default)", new Argument <bool>() )); root.AddOption(new Option( new string[] { "-i", "--ignore-garbage" }, "when decoding, ignore non-alphabet characters", new Argument <bool>() )); root.AddOption(new Option( new string[] { "-w", "--wrap" }, "wrap encoded lines after COLS characters (default 76). Use 0 to disable line wrapping", WrapArgument() )); root.AddOption(new Option( new string[] { "-f", "--file" }, "Encode or decode contents of FILE ('-' for STDIN)", FileArgument() )); root.AddOption(new Option( new string[] { "-c", "--charset" }, $"use CHARSET when decoding data from a file (Default: {Encoding.UTF8.WebName}).", CharsetArgument() )); root.AddOption(new Option( new string[] { "-b", "--buffer" }, "use SIZE as the read-buffer size. (Default: 4096)", new Argument <int>(4096) { Name = "SIZE", Description = "Size to use for intermediate read buffer" } )); root.Handler = CommandHandler.Create(typeof(Program).GetMethod(nameof(InvokeAsync))); return(root); Argument <int?> WrapArgument() { var arg = new Argument <int?>(symbol => { if (symbol.Arguments.FirstOrDefault().TryNotNull(out string value)) { try { int number = int.Parse(value, NumberStyles.Integer, CultureInfo.CurrentCulture); return(ArgumentResult.Success <int?>(number)); } catch (OverflowException overflowExcept) { return(ArgumentResult.Failure(overflowExcept.Message)); } catch (FormatException formatExcept) { return(ArgumentResult.Failure(formatExcept.Message)); } } return(ArgumentResult.Success <int?>(76)); }) { Name = "COLS", Description = $"Number of characters per line (default {76})", Arity = ArgumentArity.ZeroOrOne }; arg.SetDefaultValue(null); arg.AddValidator(symbol => symbol.Arguments.Select(s => { if (int.TryParse(s, NumberStyles.Any, CultureInfo.CurrentCulture, out int v) && v >= 0) { return(null); } return($"Argument '{s}' for option '{symbol.Token}' is invalid. Expected a non-negative integer value."); }).Where(msg => !string.IsNullOrWhiteSpace(msg)).FirstOrDefault()); return(arg); } Argument <FileInfo> FileArgument() { var argument = new Argument <FileInfo> { Name = "FILE", Description = "Path to read from or write to", Arity = ArgumentArity.ExactlyOne }; argument.AddValidator(symbol => { IEnumerable <string> source = from filePath in symbol.Arguments where !filePath.Equals("-", StringComparison.Ordinal) where !File.Exists(filePath) select filePath; ValidationMessages validationMessages = symbol.ValidationMessages; return(source.Select(validationMessages.FileDoesNotExist).FirstOrDefault()); }); return(argument); } Argument <Encoding> CharsetArgument() { var arg = new Argument <Encoding>(ConvertToEncoding) { Arity = ArgumentArity.ZeroOrOne, Name = "CHARSET", Description = $"IANA charset name (default: {Encoding.UTF8})" }; arg.AddSuggestions(Encoding.GetEncodings().Select(enc => enc.Name).ToArray()); arg.SetDefaultValue(Encoding.UTF8); return(arg); ArgumentResult ConvertToEncoding(SymbolResult symbol) { if (symbol.Arguments.FirstOrDefault().TryNotNullOrWhiteSpace(out string charset)) { try { var encoding = Encoding.GetEncoding(charset); return(ArgumentResult.Success(encoding)); } catch (ArgumentException) { return(ArgumentResult.Failure($"Argument '{charset}' for option '{symbol.Token}' is invalid. '{charset}' is not a supported encoding name.")); } } return(ArgumentResult.Success(Encoding.UTF8)); } } } }