public void InvalidUseOfGetCompletions()
        {
            var type = (TupleArgumentType)ArgumentType.GetType(typeof(Tuple <bool, bool>));
            var c    = new ArgumentCompletionContext {
                ParseContext = ArgumentParseContext.Default
            };

            type.Invoking(t => t.GetCompletions(null, "Tr")).Should().Throw <ArgumentNullException>();
            type.Invoking(t => t.GetCompletions(c, null)).Should().Throw <ArgumentNullException>();
        }
示例#2
0
        /// <inheritdoc/>
        public IEnumerable <string> GetCompletions(ArgumentCompletionContext context, string valueToComplete)
        {
            // We get the entire command line here, including the token that triggered
            // the help command to be invoked.  Any options to the help command would
            // also be present, which would pose a problem in the future if we add
            // more options to the help command.
            const int tokensToSkip = 1;

            return(_loop.GetCompletions(context.Tokens.Skip(tokensToSkip), context.TokenIndex - tokensToSkip));
        }
        public void GetCompletions()
        {
            var type = (TupleArgumentType)ArgumentType.GetType(typeof(Tuple <bool, int, bool>));
            var c    = new ArgumentCompletionContext {
                ParseContext = ArgumentParseContext.Default
            };

            type.GetCompletions(c, "Tr").Should().Equal("True");
            type.GetCompletions(c, string.Empty).Should().Equal("False", "True");
            type.GetCompletions(c, "False,3").Should().BeEmpty();
            type.GetCompletions(c, "False,3,").Should().Equal("False,3,False", "False,3,True");
        }
示例#4
0
        /// <summary>
        /// Generate possible completions of this argument that start with the
        /// provided string prefix.
        /// </summary>
        /// <param name="tokens">The set of tokens in the input being completed.
        /// </param>
        /// <param name="indexOfTokenToComplete">The 0-based index of the token
        /// to complete.</param>
        /// <param name="valueToComplete">The prefix string.</param>
        /// <param name="inProgressParsedObject">Optionally, the object
        /// resulting from parsing and processing the tokens before the one
        /// being completed.</param>
        /// <returns>Possible completions.</returns>
        public IEnumerable <string> GetCompletions(IReadOnlyList <string> tokens, int indexOfTokenToComplete, string valueToComplete, object inProgressParsedObject)
        {
            var context = new ArgumentCompletionContext
            {
                ParseContext           = ParseContext,
                Tokens                 = tokens,
                TokenIndex             = indexOfTokenToComplete,
                InProgressParsedObject = inProgressParsedObject,
                CaseSensitive          = ArgumentSet.Attribute.CaseSensitive
            };

            return(Argument.ArgumentType.GetCompletions(context, valueToComplete));
        }
        public void GetCompletions()
        {
            var type = (KeyValuePairArgumentType)ArgumentType.GetType(typeof(KeyValuePair <bool, bool>));
            var c    = new ArgumentCompletionContext {
                ParseContext = ArgumentParseContext.Default
            };

            type.GetCompletions(c, "Tr").Should().Equal("True");
            type.GetCompletions(c, string.Empty).Should().Equal("False", "True");
            type.GetCompletions(c, "False=f").Should().Equal("False=False");
            type.GetCompletions(c, "33=f").Should().Equal("33=False");
            type.GetCompletions(c, "True=").Should().Equal("True=False", "True=True");
        }
示例#6
0
        public void GetCompletionsWithValidSeparators()
        {
            var type = (ArrayArgumentType)ArgumentType.GetType(typeof(bool[]));
            var c    = new ArgumentCompletionContext {
                ParseContext = ArgumentParseContext.Default
            };

            type.GetCompletions(c, "Tr").Should().Equal("True");
            type.GetCompletions(c, string.Empty).Should().Equal("False", "True");
            type.GetCompletions(c, "False,f").Should().Equal("False,False");
            type.GetCompletions(c, "33,f").Should().Equal("33,False");
            type.GetCompletions(c, "True,False,").Should().Equal("True,False,False", "True,False,True");
        }
示例#7
0
        public void InvalidUseOfGetCompletions()
        {
            var type = (ArrayArgumentType)ArgumentType.GetType(typeof(bool[]));
            var c    = new ArgumentCompletionContext {
                ParseContext = ArgumentParseContext.Default
            };

            Action badContext = () => type.GetCompletions(null, "Tr");

            badContext.Should().Throw <ArgumentNullException>();

            Action badValue = () => type.GetCompletions(c, null);

            badValue.Should().Throw <ArgumentNullException>();
        }
示例#8
0
        public void GetCompletionsWithoutValidSeparators()
        {
            var type = (ArrayArgumentType)ArgumentType.GetType(typeof(bool[]));
            var c    = new ArgumentCompletionContext
            {
                ParseContext = new ArgumentParseContext
                {
                    ElementSeparators = Array.Empty <string>()
                }
            };

            type.GetCompletions(c, "Tr").Should().Equal("True");
            type.GetCompletions(c, string.Empty).Should().Equal("False", "True");
            type.GetCompletions(c, "False,f").Should().BeEmpty();
            type.GetCompletions(c, "33,f").Should().BeEmpty();
            type.GetCompletions(c, "True,False,").Should().BeEmpty();
        }
示例#9
0
 public IEnumerable <string> GetCompletions(ArgumentCompletionContext context, string valueToComplete) =>
 new[] { "|a|", "|ABC|" };
        /// <summary>
        /// Generate possible completions for the specified token in the
        /// provided set of input tokens.
        /// </summary>
        /// <param name="tokens">The tokens.</param>
        /// <param name="indexOfTokenToComplete">Index of the token to complete.
        /// </param>
        /// <param name="destObjectFactory">If non-null, provides a factory
        /// function that can be used to create an object suitable to being
        /// filled out by this parser instance.</param>
        /// <returns>The candidate completions for the specified token.
        /// </returns>
        public IEnumerable <string> GetCompletions(IEnumerable <string> tokens, int indexOfTokenToComplete, Func <object> destObjectFactory)
        {
            Func <IEnumerable <string> > emptyCompletions = Enumerable.Empty <string>;

            var tokenList = tokens.ToList();

            // Complain bitterly if we were asked to complete something far beyond
            // the token list we received.
            if (indexOfTokenToComplete > tokenList.Count)
            {
                throw new ArgumentOutOfRangeException(nameof(indexOfTokenToComplete));
            }

            // If we were asked to complete the token just after the list we received,
            // then this means we're generating completions to append to the full
            // token list.  Insert an empty token and use that as the basis for
            // completion.
            if (indexOfTokenToComplete == tokenList.Count)
            {
                tokenList = tokenList.Concat(new[] { string.Empty }).ToList();
            }

            // Figure out the token we're going to complete.
            var tokenToComplete = tokenList[indexOfTokenToComplete];

            // Create a destination object if provided with a factory.
            var inProgressParsedObject = destObjectFactory?.Invoke();

            // Parse what we've seen thus far (before the token /to complete).
            // Note that this parse attempt may fail; we ignore success/failure.
            var tokensToParse = tokenList.Take(indexOfTokenToComplete).ToList();
            var parseResult   = ParseArgumentList(tokensToParse, inProgressParsedObject);

            // See if we're expecting this token to be an option argument; if
            // so, then we can generate completions based on that.
            if (parseResult.State == TokenParseResultState.RequiresOptionArgument &&
                _argumentSet.Attribute.AllowNamedArgumentValueAsSucceedingToken)
            {
                return(parseResult.Argument.GetCompletions(
                           tokenList,
                           indexOfTokenToComplete,
                           tokenToComplete,
                           inProgressParsedObject));
            }

            // See if the token to complete appears to be a (long-)named argument.
            var longNameArgumentPrefix = TryGetLongNameArgumentPrefix(tokenToComplete);

            if (longNameArgumentPrefix != null)
            {
                var afterPrefix = tokenToComplete.Substring(longNameArgumentPrefix.Length);
                return(GetNamedArgumentCompletions(tokenList, indexOfTokenToComplete, afterPrefix, inProgressParsedObject)
                       .Select(completion => longNameArgumentPrefix + completion));
            }

            // See if the token to complete appears to be a (short-)named argument.
            var shortNameArgumentPrefix = TryGetShortNameArgumentPrefix(tokenToComplete);

            if (shortNameArgumentPrefix != null)
            {
                var afterPrefix = tokenToComplete.Substring(shortNameArgumentPrefix.Length);
                return(GetNamedArgumentCompletions(tokenList, indexOfTokenToComplete, afterPrefix, inProgressParsedObject)
                       .Select(completion => shortNameArgumentPrefix + completion));
            }

            // See if the token to complete appears to be the special answer-file argument.
            var answerFileArgumentPrefix = TryGetAnswerFilePrefix(tokenToComplete);

            if (answerFileArgumentPrefix != null)
            {
                var filePath     = tokenToComplete.Substring(answerFileArgumentPrefix.Length);
                var parseContext = new ArgumentParseContext
                {
                    FileSystemReader = _options.FileSystemReader,
                    ParserContext    = _options.Context,
                    CaseSensitive    = _argumentSet.Attribute.CaseSensitive
                };

                var completionContext = new ArgumentCompletionContext
                {
                    ParseContext           = parseContext,
                    TokenIndex             = indexOfTokenToComplete,
                    Tokens                 = tokenList,
                    InProgressParsedObject = inProgressParsedObject,
                    CaseSensitive          = _argumentSet.Attribute.CaseSensitive
                };

                return(ArgumentType.FileSystemPath.GetCompletions(completionContext, filePath)
                       .Select(completion => answerFileArgumentPrefix + completion));
            }

            // At this point, assume it must be a positional argument. If it's not, then there's not much
            // that we can do.
            if (!_argumentSet.TryGetPositionalArgument(_nextPositionalArgIndexToParse, out ArgumentDefinition positionalArg))
            {
                return(emptyCompletions());
            }

            return(positionalArg.GetCompletions(
                       tokenList,
                       indexOfTokenToComplete,
                       tokenToComplete,
                       inProgressParsedObject));
        }
示例#11
0
        /// <summary>
        /// Generates possible completions for the indicated argument token.
        /// </summary>
        /// <param name="tokens">Full list of tokens in context.</param>
        /// <param name="indexOfTokenToComplete">0-based index of token
        /// to complete; must either reference valid token in <paramref name="tokens"/>
        /// or the index of the next token that would follow the provided
        /// tokens.</param>
        /// <param name="destObjectFactory">Optionally provides a function
        /// that may be used to instantiate an object of the destination
        /// parse output type.</param>
        /// <returns>Possible completions for the token.</returns>
        public IEnumerable <string> GetCompletions(IEnumerable <string> tokens, int indexOfTokenToComplete, Func <object> destObjectFactory)
        {
            Func <IEnumerable <string> > emptyCompletions = Enumerable.Empty <string>;

            var tokenList = tokens.ToList();

            // Complain bitterly if we were asked to complete something far beyond
            // the token list we received.
            if (indexOfTokenToComplete > tokenList.Count)
            {
                throw new ArgumentOutOfRangeException(nameof(indexOfTokenToComplete));
            }

            // If we were asked to complete the token just after the list we received,
            // then this means we're generating completions to append to the full
            // token list.  Insert an empty token and use that as the basis for
            // completion.
            if (indexOfTokenToComplete == tokenList.Count)
            {
                tokenList = tokenList.Concat(new[] { string.Empty }).ToList();
            }

            // Figure out the token we're going to complete.
            var tokenToComplete = tokenList[indexOfTokenToComplete];

            // Create a destination object if provided with a factory.
            var inProgressParsedObject = destObjectFactory?.Invoke();

            // Parse what we've seen thus far (before the token /to complete).
            // Note that this parse attempt may fail; we ignore success/failure.
            var tokensToParse = tokenList.Take(indexOfTokenToComplete).ToList();
            var parseResult   = ParseArgumentList(tokensToParse, inProgressParsedObject);

            // See if we're expecting this token to be an option argument; if
            // so, then we can generate completions based on that.
            bool completeViaLastArg = false;

            if (parseResult.State == ArgumentSetParseResultType.RequiresOptionArgument &&
                ArgumentSet.Attribute.AllowNamedArgumentValueAsSucceedingToken)
            {
                completeViaLastArg = true;
            }

            // See if we just finished parsing an argument that takes the rest
            // of the line.
            if (parseResult.LastSeenArg?.TakesRestOfLine ?? false)
            {
                completeViaLastArg = true;
            }

            // If we can complete via the last seen argument, then construct a parser
            // around the argument and generate the completions.
            if (completeViaLastArg)
            {
                var argParseState = new ArgumentParser(ArgumentSet, parseResult.LastSeenArg, _options, /*destination=*/ null);
                return(argParseState.GetCompletions(
                           tokenList,
                           indexOfTokenToComplete,
                           tokenToComplete,
                           inProgressParsedObject));
            }

            // See if the token to complete appears to be a named argument.
            var longNameArgumentPrefix  = TryGetLongNameArgumentPrefix(tokenToComplete, allowIncompleteToken: true);
            var shortNameArgumentPrefix = TryGetShortNameArgumentPrefix(tokenToComplete, allowIncompleteToken: true);

            if (longNameArgumentPrefix != null || shortNameArgumentPrefix != null)
            {
                var completions = Enumerable.Empty <string>();

                if (longNameArgumentPrefix != null)
                {
                    var prefixLen       = Math.Min(longNameArgumentPrefix.Length, tokenToComplete.Length);
                    var afterLongPrefix = tokenToComplete.Substring(prefixLen);
                    completions = completions.Concat(
                        GetNamedArgumentCompletions(ArgumentNameType.LongName, tokenList, indexOfTokenToComplete, afterLongPrefix, inProgressParsedObject)
                        .Select(completion => longNameArgumentPrefix + completion));
                }

                if (shortNameArgumentPrefix != null)
                {
                    var prefixLen        = Math.Min(shortNameArgumentPrefix.Length, tokenToComplete.Length);
                    var afterShortPrefix = tokenToComplete.Substring(prefixLen);
                    completions = completions.Concat(
                        GetNamedArgumentCompletions(ArgumentNameType.ShortName, tokenList, indexOfTokenToComplete, afterShortPrefix, inProgressParsedObject)
                        .Select(completion => shortNameArgumentPrefix + completion));
                }

                return(completions);
            }

            // See if the token to complete appears to be the special answer-file argument.
            var answerFileArgumentPrefix = TryGetAnswerFilePrefix(tokenToComplete);

            if (answerFileArgumentPrefix != null)
            {
                var filePath     = tokenToComplete.Substring(answerFileArgumentPrefix.Length);
                var parseContext = new ArgumentParseContext
                {
                    FileSystemReader  = _options.FileSystemReader,
                    ParserContext     = _options.Context,
                    ServiceConfigurer = _options.ServiceConfigurer,
                    CaseSensitive     = ArgumentSet.Attribute.CaseSensitive
                };

                var completionContext = new ArgumentCompletionContext
                {
                    ParseContext           = parseContext,
                    TokenIndex             = indexOfTokenToComplete,
                    Tokens                 = tokenList,
                    InProgressParsedObject = inProgressParsedObject,
                    CaseSensitive          = ArgumentSet.Attribute.CaseSensitive
                };

                return(ArgumentType.FileSystemPath.GetCompletions(completionContext, filePath)
                       .Select(completion => answerFileArgumentPrefix + completion));
            }

            // At this point, assume it must be a positional argument. If it's not, then there's not much
            // that we can do.
            if (!ArgumentSet.TryGetPositionalArgument(NextPositionalArgIndexToParse, out ArgumentDefinition positionalArg))
            {
                return(emptyCompletions());
            }

            var parseState = new ArgumentParser(ArgumentSet, positionalArg, _options, /*destination=*/ null);

            return(parseState.GetCompletions(
                       tokenList,
                       indexOfTokenToComplete,
                       tokenToComplete,
                       inProgressParsedObject));
        }