예제 #1
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);
        }
        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);
        }
        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);
        }
예제 #4
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);
            }
        }
        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));
        }
예제 #6
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 (!Constants.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);
        }
예제 #7
0
 internal static CommandParseException Create(string arguments, CommandTreeToken token, string message, string details)
 {
     return(new CommandParseException(message, CreatePrettyMessage(arguments, token, message, details)));
 }
예제 #8
0
 internal static CommandParseException Create(IEnumerable <string> arguments, CommandTreeToken token, string message, string details)
 {
     return(new CommandParseException(message, CreatePrettyMessage(string.Join(" ", arguments), token, message, details)));
 }