public async Task <Suggestions> GetCompletionSuggestions(ParseResults <TSource> parse, int cursor) { var context = parse.Context; var nodeBeforeCursor = context.FindSuggestionContext(cursor); var parent = nodeBeforeCursor.Parent; var start = Math.Min(nodeBeforeCursor.StartPos, cursor); var fullInput = parse.Reader.String; var truncatedInput = fullInput.Substring(0, cursor); var truncatedInputLowerCase = truncatedInput.ToLowerInvariant(); var futures = new Task <Suggestions> [parent.Children.Count()]; var i = 0; foreach (var node in parent.Children) { var future = Suggestions.Empty(); try { future = node.ListSuggestions(context.Build(truncatedInput), new SuggestionsBuilder(truncatedInput, truncatedInputLowerCase, start)); } catch (CommandSyntaxException) { } futures[i++] = future; } await Task.WhenAll(futures); return(Suggestions.Merge(fullInput, futures.Select(s => s.Result).ToArray())); }
/** * Gets suggestions for a parsed input string on what comes next. * * <p>As it is ultimately up to custom argument types to provide suggestions, it may be an asynchronous operation, * for example getting in-game data or player names etc. As such, this method returns a future and no guarantees * are made to when or how the future completes.</p> * * <p>The suggestions provided will be in the context of the end of the parsed input string, but may suggest * new or replacement strings for earlier in the input string. For example, if the end of the string was * {@code foobar} but an argument preferred it to be {@code minecraft:foobar}, it will suggest a replacement for that * whole segment of the input.</p> * * @param parse the result of a {@link #parse(StringReader, Object)} * @return a future that will eventually resolve into a {@link Suggestions} object */ public Task <Suggestions> GetCompletionSuggestions(ParseResults <TSource> parse) { return(GetCompletionSuggestions(parse, parse.Reader.TotalLength)); }
/** * Executes a given pre-parsed command. * * <p>If this command returns a value, then it successfully executed something. If the execution was a failure, * then an exception will be thrown. * Most exceptions will be of type {@link CommandSyntaxException}, but it is possible that a {@link RuntimeException} * may bubble up from the result of a command. The meaning behind the returned result is arbitrary, and will depend * entirely on what command was performed.</p> * * <p>If the command passes through a node that is {@link CommandNode#isFork()} then it will be 'forked'. * A forked command will not bubble up any {@link CommandSyntaxException}s, and the 'result' returned will turn into * 'amount of successful commands executes'.</p> * * <p>After each and any command is ran, a registered callback given to {@link #setConsumer(ResultConsumer)} * will be notified of the result and success of the command. You can use that method to gather more meaningful * results than this method will return, especially when a command forks.</p> * * @param parse the result of a successful {@link #parse(StringReader, Object)} * @return a numeric result from a "command" that was performed. * @throws CommandSyntaxException if the command failed to parse or execute * @throws RuntimeException if the command failed to execute and was not handled gracefully * @see #parse(String, Object) * @see #parse(StringReader, Object) * @see #execute(String, Object) * @see #execute(StringReader, Object) */ ///<exception cref="CommandSyntaxException" /> public int Execute(ParseResults <TSource> parse) { if (parse.Reader.CanRead()) { if (parse.Exceptions.Count == 1) { throw parse.Exceptions.Values.Single(); } else if (parse.Context.Range.IsEmpty) { throw CommandSyntaxException.BuiltInExceptions.DispatcherUnknownCommand().CreateWithContext(parse.Reader); } else { throw CommandSyntaxException.BuiltInExceptions.DispatcherUnknownArgument().CreateWithContext(parse.Reader); } } var result = 0; var successfulForks = 0; var forked = false; var foundCommand = false; var command = parse.Reader.String; var original = parse.Context.Build(command); var contexts = new List <CommandContext <TSource> > { original }; List <CommandContext <TSource> > next = null; while (contexts != null) { var size = contexts.Count; for (var i = 0; i < size; i++) { var context = contexts[i]; var child = context.Child; if (child != null) { forked |= context.IsForked(); if (child.HasNodes()) { foundCommand = true; var modifier = context.RedirectModifier; if (modifier == null) { if (next == null) { next = new List <CommandContext <TSource> >(1); } next.Add(child.CopyFor(context.Source)); } else { try { var results = modifier(context); if (results.Count > 0) { if (next == null) { next = new List <CommandContext <TSource> >(results.Count()); } foreach (var source in results) { next.Add(child.CopyFor(source)); } } } catch (CommandSyntaxException) { Consumer(context, false, 0); if (!forked) { throw; } } } } } else if (context.Command != null) { foundCommand = true; try { var value = context.Command(context); result += value; Consumer(context, true, value); successfulForks++; } catch (CommandSyntaxException) { Consumer(context, false, 0); if (!forked) { throw; } } } } contexts = next; next = null; } if (!foundCommand) { Consumer(original, false, 0); throw CommandSyntaxException.BuiltInExceptions.DispatcherUnknownCommand().CreateWithContext(parse.Reader); } return(forked ? successfulForks : result); }