Beispiel #1
0
        public static ParseException LongOptionNameContainSymbol(TextBuffer reader, int position, char character)
        {
            var name  = character.ToString();
            var token = new CommandTreeToken(CommandTreeToken.Kind.LongOption, position, name, name);

            return(ParseExceptionFactory.Create(reader.Original, token, "Invalid long option name.", "Invalid character."));
        }
        private static IRenderable CreatePrettyMessage(string arguments, CommandTreeToken token, string message, string details)
        {
            var composer = new RenderableComposer();

            var position = token?.Position ?? 0;
            var value    = token?.Representation ?? arguments;

            // Header
            composer.LineBreak();
            composer.Color(ConsoleColor.Red, error => error.Text("Error:"));
            composer.Space().Text(message);
            composer.LineBreak();

            // Template
            composer.LineBreak();
            composer.Spaces(7).Text(arguments);

            // Error
            composer.LineBreak();
            composer.Spaces(7).Spaces(position);
            composer.Color(ConsoleColor.Red, error =>
            {
                error.Repeat('^', value.Length);
                error.Text($" {details.TrimEnd('.')}");
                error.LineBreak();
            });

            composer.LineBreak();

            return(composer);
        }
Beispiel #3
0
        public static ParseException LongOptionNameIsOneCharacter(TextBuffer reader, int position, string name)
        {
            var token  = new CommandTreeToken(CommandTreeToken.Kind.LongOption, position, name, $"--{name}");
            var reason = $"Did you mean -{name}?";

            return(ParseExceptionFactory.Create(reader.Original, token, "Invalid long option name.", reason));
        }
Beispiel #4
0
    private static IRenderable CreatePrettyMessage(string arguments, CommandTreeToken token, string message, string details)
    {
        var composer = new Composer();

        var position = token?.Position ?? 0;
        var value    = token?.Representation ?? arguments;

        // Header
        composer.LineBreak();
        composer.Style("red", "Error:");
        composer.Space().Text(message.EscapeMarkup());
        composer.LineBreak();

        // Template
        composer.LineBreak();
        composer.Spaces(7).Text(arguments.EscapeMarkup());

        // Error
        composer.LineBreak();
        composer.Spaces(7).Spaces(position);

        composer.Style("red", error =>
        {
            error.Repeat('^', value.Length);
            error.Space();
            error.Text(details.TrimEnd('.').EscapeMarkup());
            error.LineBreak();
        });

        composer.LineBreak();

        return(composer);
    }
Beispiel #5
0
    private static IEnumerable <CommandTreeToken> ScanOptions(CommandTreeTokenizerContext context, TextBuffer reader)
    {
        var result = new List <CommandTreeToken>();

        var position = reader.Position;

        reader.Consume('-');
        context.AddRemaining('-');

        if (!reader.TryPeek(out var character))
        {
            var token = new CommandTreeToken(CommandTreeToken.Kind.ShortOption, position, "-", "-");
            throw CommandParseException.OptionHasNoName(reader.Original, token);
        }

        switch (character)
        {
        case '-':
            var option = ScanLongOption(context, reader, position);
            if (option != null)
            {
                result.Add(option);
            }

            break;

        default:
            result.AddRange(ScanShortOptions(context, reader, position));
            break;
        }

        if (reader.TryPeek(out character))
        {
            // Encountered a separator?
            if (character == '=' || character == ':')
            {
                reader.Read(); // Consume
                context.AddRemaining(character);

                if (!reader.TryPeek(out _))
                {
                    var token = new CommandTreeToken(CommandTreeToken.Kind.String, reader.Position, "=", "=");
                    throw CommandParseException.OptionValueWasExpected(reader.Original, token);
                }

                result.Add(ScanString(context, reader));
            }
        }

        return(result);
    }
Beispiel #6
0
    private static IEnumerable <CommandTreeToken> ScanShortOptions(CommandTreeTokenizerContext context, TextBuffer reader, int position)
    {
        var result = new List <CommandTreeToken>();

        while (!reader.ReachedEnd)
        {
            var current = reader.Peek();
            if (char.IsWhiteSpace(current))
            {
                break;
            }

            // Encountered a separator?
            if (current == '=' || current == ':')
            {
                break;
            }

            if (char.IsLetter(current))
            {
                context.AddRemaining(current);
                reader.Read(); // Consume

                var value = current.ToString(CultureInfo.InvariantCulture);
                result.Add(result.Count == 0
                    ? new CommandTreeToken(CommandTreeToken.Kind.ShortOption, position, value, $"-{value}")
                    : new CommandTreeToken(CommandTreeToken.Kind.ShortOption, position + result.Count, value, value));
            }
            else
            {
                // Create a token representing the short option.
                var tokenPosition = position + 1 + result.Count;
                var represntation = current.ToString(CultureInfo.InvariantCulture);
                var token         = new CommandTreeToken(CommandTreeToken.Kind.ShortOption, tokenPosition, represntation, represntation);
                throw CommandParseException.InvalidShortOptionName(reader.Original, token);
            }
        }

        if (result.Count > 1)
        {
            foreach (var item in result)
            {
                item.IsGrouped = true;
            }
        }

        return(result);
    }
Beispiel #7
0
    private void ParseOption(
        CommandTreeParserContext context,
        CommandTreeTokenStream stream,
        CommandTreeToken token,
        CommandTree node,
        bool isLongOption)
    {
        // Consume the option token.
        stream.Consume(isLongOption ? CommandTreeToken.Kind.LongOption : CommandTreeToken.Kind.ShortOption);

        if (context.State == State.Normal)
        {
            // Find the option.
            var option = node.FindOption(token.Value, isLongOption, CaseSensitivity);
            if (option != null)
            {
                node.Mapped.Add(new MappedCommandParameter(
                                    option, ParseOptionValue(context, stream, token, node, option)));

                return;
            }

            // Help?
            if (_help?.IsMatch(token.Value) == true)
            {
                node.ShowHelp = true;
                return;
            }
        }

        if (context.State == State.Remaining)
        {
            ParseOptionValue(context, stream, token, node, null);
            return;
        }

        if (context.ParsingMode == ParsingMode.Strict)
        {
            throw CommandParseException.UnknownOption(context.Arguments, token);
        }
        else
        {
            ParseOptionValue(context, stream, token, node, null);
        }
    }
Beispiel #8
0
    private static CommandTreeToken ScanQuotedString(CommandTreeTokenizerContext context, TextBuffer reader)
    {
        var position = reader.Position;

        context.FlushRemaining();
        reader.Consume('\"');

        var builder    = new StringBuilder();
        var terminated = false;

        while (!reader.ReachedEnd)
        {
            var character = reader.Peek();
            if (character == '\"')
            {
                terminated = true;
                reader.Read();
                break;
            }

            builder.Append(reader.Read());
        }

        if (!terminated)
        {
            var unterminatedQuote = builder.ToString();
            var token             = new CommandTreeToken(CommandTreeToken.Kind.String, position, unterminatedQuote, $"\"{unterminatedQuote}");
            throw CommandParseException.UnterminatedQuote(reader.Original, token);
        }

        var quotedString = builder.ToString();

        // Add to the context
        context.AddRemaining(quotedString);

        return(new CommandTreeToken(
                   CommandTreeToken.Kind.String,
                   position, quotedString,
                   quotedString));
    }
Beispiel #9
0
 public static ParseException UnexpectedOption(IEnumerable <string> args, CommandTreeToken token)
 {
     return(ParseExceptionFactory.Create(args, token, $"Unexpected option '{token.Value}'.", "Did you forget the command?"));
 }
 internal static ParseException Create(IEnumerable <string> arguments, CommandTreeToken token, string message, string details)
 {
     return(new ParseException(message, CreatePrettyMessage(string.Join(" ", arguments), token, message, details)));
 }
Beispiel #11
0
 public static ParseException UnterminatedQuote(string input, CommandTreeToken token)
 {
     return(ParseExceptionFactory.Create(input, token, $"Encountered unterminated quoted string '{token.Value}'.", "Did you forget the closing quotation mark?"));
 }
 internal static ParseException Create(string arguments, CommandTreeToken token, string message, string details)
 {
     return(new ParseException(message, CreatePrettyMessage(arguments, token, message, details)));
 }
Beispiel #13
0
        public static ParseException LongOptionNameStartWithDigit(TextBuffer reader, int position, string name)
        {
            var token = new CommandTreeToken(CommandTreeToken.Kind.LongOption, position, name, $"--{name}");

            return(ParseExceptionFactory.Create(reader.Original, token, "Invalid long option name.", "Option names cannot start with a digit."));
        }
Beispiel #14
0
        public static ParseException UnknownCommand(CommandModel model, CommandTree node, IEnumerable <string> args, CommandTreeToken token)
        {
            var availableCommands = node?.Command ?? (ICommandContainer)model;
            var suggestion        = CommandSuggestor.Suggest(model, node?.Command, token.Value);

            var text = suggestion != null ? $"Did you mean '{suggestion.Name}'?" : "No such command.";

            return(ParseExceptionFactory.Create(args, token, $"Unknown command '{token.Value}'.", text));
        }
Beispiel #15
0
        public static ParseException LongOptionNameIsMissing(TextBuffer reader, int position)
        {
            var token = new CommandTreeToken(CommandTreeToken.Kind.LongOption, position, string.Empty, "--");

            return(ParseExceptionFactory.Create(reader.Original, token, "Invalid long option name.", "Did you forget the option name?"));
        }
Beispiel #16
0
 public static ParseException InvalidShortOptionName(string input, CommandTreeToken token)
 {
     return(ParseExceptionFactory.Create(input, token, "Short option does not have a valid name.", "Not a valid name for a short option."));
 }
Beispiel #17
0
    internal static CommandParseException UnknownCommand(CommandModel model, CommandTree?node, IEnumerable <string> args, CommandTreeToken token)
    {
        var suggestion = CommandSuggestor.Suggest(model, node?.Command, token.Value);
        var text       = suggestion != null ? $"Did you mean '{suggestion.Name}'?" : "No such command.";

        return(CommandLineParseExceptionFactory.Create(args, token, $"Unknown command '{token.Value}'.", text));
    }
Beispiel #18
0
 public static ParseException OptionHasNoValue(IEnumerable <string> args, CommandTreeToken token, CommandOption option)
 {
     return(ParseExceptionFactory.Create(args, token, $"Option '{option.GetOptionName()}' is defined but no value has been provided.", "No value provided."));
 }
Beispiel #19
0
 public static ParseException OptionValueWasExpected(string input, CommandTreeToken token)
 {
     return(ParseExceptionFactory.Create(input, token, "Expected an option value.", "Did you forget the option value?"));
 }
Beispiel #20
0
 public static ParseException OptionHasNoName(string input, CommandTreeToken token)
 {
     return(ParseExceptionFactory.Create(input, token, "Option does not have a name.", "Did you forget the option name?"));
 }
Beispiel #21
0
 public static ParseException UnknownOption(IEnumerable <string> args, CommandTreeToken token)
 {
     return(ParseExceptionFactory.Create(args, token, $"Unknown option '{token.Value}'.", "Unknown option."));
 }
Beispiel #22
0
 public static ParseException CouldNotMatchArgument(IEnumerable <string> args, CommandTreeToken token)
 {
     return(ParseExceptionFactory.Create(args, token, $"Could not match '{token.Value}' with an argument.", "Could not match to argument."));
 }
Beispiel #23
0
    private string?ParseOptionValue(
        CommandTreeParserContext context,
        CommandTreeTokenStream stream,
        CommandTreeToken token,
        CommandTree current,
        CommandParameter?parameter)
    {
        var value = default(string);

        // Parse the value of the token (if any).
        var valueToken = stream.Peek();

        if (valueToken?.TokenKind == CommandTreeToken.Kind.String)
        {
            var parseValue = true;
            if (token.TokenKind == CommandTreeToken.Kind.ShortOption && token.IsGrouped)
            {
                parseValue = false;
            }

            if (context.State == State.Normal && parseValue)
            {
                // Is this a command?
                if (current.Command.FindCommand(valueToken.Value, CaseSensitivity) == null)
                {
                    if (parameter != null)
                    {
                        if (parameter.ParameterKind == ParameterKind.Flag)
                        {
                            if (!CliConstants.AcceptedBooleanValues.Contains(valueToken.Value, StringComparer.OrdinalIgnoreCase))
                            {
                                // Flags cannot be assigned a value.
                                throw CommandParseException.CannotAssignValueToFlag(context.Arguments, token);
                            }
                        }

                        value = stream.Consume(CommandTreeToken.Kind.String)?.Value;
                    }
                    else
                    {
                        // Unknown parameter value.
                        value = stream.Consume(CommandTreeToken.Kind.String)?.Value;

                        // In relaxed parsing mode?
                        if (context.ParsingMode == ParsingMode.Relaxed)
                        {
                            context.AddRemainingArgument(token.Value, value);
                        }
                    }
                }
            }
            else
            {
                context.AddRemainingArgument(token.Value, parseValue ? valueToken.Value : null);
            }
        }
        else
        {
            if (context.State == State.Remaining || context.ParsingMode == ParsingMode.Relaxed)
            {
                context.AddRemainingArgument(token.Value, null);
            }
        }

        // No value?
        if (context.State == State.Normal)
        {
            if (value == null && parameter != null)
            {
                if (parameter.ParameterKind == ParameterKind.Flag)
                {
                    value = "true";
                }
                else
                {
                    if (parameter is CommandOption option)
                    {
                        if (parameter.IsFlagValue())
                        {
                            return(null);
                        }

                        throw CommandParseException.OptionHasNoValue(context.Arguments, token, option);
                    }
                    else
                    {
                        // This should not happen at all. If it does, it's because we've added a new
                        // option type which isn't a CommandOption for some reason.
                        throw new InvalidOperationException($"Found invalid parameter type '{parameter.GetType().FullName}'.");
                    }
                }
            }
        }

        return(value);
    }
Beispiel #24
0
 public static ParseException CannotAssignValueToFlag(IEnumerable <string> args, CommandTreeToken token)
 {
     return(ParseExceptionFactory.Create(args, token, "Flags cannot be assigned a value.", "Can't assign value."));
 }