Skip to content

Commit

Permalink
Fixed 1.8 bukkit auto-completion bugs
Browse files Browse the repository at this point in the history
  • Loading branch information
Mqzn committed Oct 24, 2024
1 parent 59bc6c1 commit b807d56
Show file tree
Hide file tree
Showing 13 changed files with 92 additions and 33 deletions.
13 changes: 10 additions & 3 deletions bukkit/src/main/java/dev/velix/imperat/InternalBukkitCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import org.jetbrains.annotations.Nullable;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

@ApiStatus.Internal
Expand Down Expand Up @@ -81,10 +82,16 @@ public boolean execute(@NotNull CommandSender sender,
final @NotNull String alias,
final String[] args
) throws IllegalArgumentException {
//ImperatDebugger.debug("Starting bukkit tab-completion");
BukkitSource source = dispatcher.wrapSender(sender);
var completions = dispatcher.autoComplete(command, source, args).join();
if (completions instanceof List<String> list) return list;
else return new ArrayList<>(completions);
try {
var completions = dispatcher.autoComplete(command, source, args).join();
//ImperatDebugger.debug("Size of completions= %s", completions.size());
return new ArrayList<>(completions);
} catch (Exception ex) {
ex.printStackTrace();
return Collections.emptyList();
}
}

}
22 changes: 22 additions & 0 deletions bukkit/src/main/java/dev/velix/imperat/WrappedBukkitCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.List;

@ApiStatus.Internal
public final class WrappedBukkitCommand extends Command implements PermissionHolder, DescriptionHolder {

Expand Down Expand Up @@ -84,4 +86,24 @@ public void describe(Description description) {
public void permission(String permission) {
command.setPermission(permission);
}

/**
* Executed on tab completion for this command, returning a list of
* options the player can tab through.
*
* @param sender Source object which is executing this command
* @param alias the alias being used
* @param args All arguments passed to the command, split via ' '
* @return a list of tab-completions for the specified arguments. This
* will never be null. List may be immutable.
* @throws IllegalArgumentException if sender, alias, or args is null
*/
@Override
public @NotNull List<String> tabComplete(
@NotNull CommandSender sender,
@NotNull String alias,
@NotNull String[] args
) throws IllegalArgumentException {
return command.tabComplete(sender, alias, args);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public String id() {
@NotNull CommandInputStream<BukkitSource> commandInputStream
) throws ImperatException {
if (context.source().isConsole()) {
throw new SourceException("Only players can targeted !");
throw new SourceException("Only players can do this !");
}
return List.of((E) context.source().asPlayer());
}
Expand All @@ -61,7 +61,7 @@ public String id() {
@NotNull CommandInputStream<BukkitSource> commandInputStream
) throws ImperatException {
if (context.source().isConsole()) {
throw new SourceException("Only players can targeted !");
throw new SourceException("Only players can do this !");
}

Player sender = context.source().asPlayer();
Expand Down Expand Up @@ -131,7 +131,7 @@ public String id() {
@NotNull CommandInputStream<BukkitSource> commandInputStream
) throws ImperatException {
if (context.source().isConsole()) {
throw new SourceException("Only players can targeted !");
throw new SourceException("Only players can do this !");
}
Player player = context.source().asPlayer();
World world = player.getWorld();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,30 +63,35 @@ public ParameterTargetSelector() {

char last = raw.charAt(raw.length() - 1);

if (commandInputStream.currentLetter().filter((c) -> String.valueOf(c).equalsIgnoreCase(SelectionType.MENTION_CHARACTER)).isPresent()) {
if (commandInputStream.currentLetter()
.filter((c) -> String.valueOf(c).equalsIgnoreCase(SelectionType.MENTION_CHARACTER)).isEmpty()) {
Player target = Bukkit.getPlayer(raw);
if (target == null)
return TargetSelector.empty();

return TargetSelector.of(SelectionType.UNKNOWN, target);
}

if (context.source().isConsole()) {
/*if (context.source().isConsole()) {
throw new SourceException("Only players can use this");
}
}*/



SelectionType type = commandInputStream.popLetter()
.map((s) -> SelectionType.from(String.valueOf(s))).orElse(SelectionType.UNKNOWN);
//update current

if (type == SelectionType.UNKNOWN) {
throw new SourceException("Unknown selection type '%s'", commandInputStream.currentLetter());
throw new SourceException("Unknown selection type '%s'", commandInputStream.currentLetter().orElseThrow());
}

List<SelectionParameterInput<?>> inputParameters = new ArrayList<>();

boolean parameterized = commandInputStream.popLetter().map((c) -> c == PARAMETER_START).orElse(false) && last == PARAMETER_END;
if (parameterized) {
commandInputStream.skipLetter();

String params = commandInputStream.collectBeforeFirst(PARAMETER_END);
inputParameters = SelectionParameterInput.parseAll(params, commandInputStream);
}
Expand Down Expand Up @@ -151,7 +156,11 @@ public Collection<String> autoComplete(
SuggestionContext<BukkitSource> context,
CommandParameter<BukkitSource> parameter
) {
return suggestions;
//ImperatDebugger.debug("SUGGESTING for TargetSelector");
List<String> completions = new ArrayList<>(suggestions);
Bukkit.getOnlinePlayers().stream().
map(Player::getName).forEach(completions::add);
return completions;
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package dev.velix.imperat.type;

import dev.velix.imperat.BukkitSource;
import dev.velix.imperat.command.parameters.CommandParameter;
import dev.velix.imperat.command.parameters.type.BaseParameterType;
import dev.velix.imperat.context.ExecutionContext;
import dev.velix.imperat.context.internal.CommandInputStream;
Expand Down Expand Up @@ -39,6 +38,7 @@ public class ParameterWorld extends BaseParameterType<BukkitSource, World> {
}
}

@SuppressWarnings("unchecked")
public ParameterWorld(Class<?> type) {
super(TypeWrap.of((Class<World>) type));
}
Expand All @@ -53,10 +53,6 @@ public ParameterWorld(Class<?> type) {
throw new UnknownWorldException(raw);
}

@Override
public boolean matchesInput(String input, CommandParameter<BukkitSource> parameter) {
return super.matchesInput(input, parameter);
}

/**
* Returns the suggestion resolver associated with this parameter type.
Expand Down
7 changes: 6 additions & 1 deletion core/src/main/java/dev/velix/imperat/ResolverRegistrar.java
Original file line number Diff line number Diff line change
Expand Up @@ -122,9 +122,14 @@ default <T> ContextResolver<S, T> getContextResolver(CommandParameter<S> command
@SuppressWarnings("uncecked")
default @NotNull SuggestionResolver<S> getParameterSuggestionResolver(CommandParameter<S> parameter) {
SuggestionResolver<S> parameterSpecificResolver = parameter.getSuggestionResolver();
//ImperatDebugger.debug("Getting the suggestion resolver for param '%s'", parameter.format());
if (parameterSpecificResolver == null) {
//ImperatDebugger.debug("Found no specific argument suggestion resolver for param '%s'", parameter.format());
var resolverByType = getSuggestionResolverByType(parameter.valueType());
if (resolverByType != null) return resolverByType;
if (resolverByType != null) {
//ImperatDebugger.debug("Found resolver by type for param '%s'", parameter.format() );
return resolverByType;
}
else return SuggestionResolver.plain(Collections.singletonList(parameter.format()));
} else
return parameterSpecificResolver;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ private void regDefThrowableResolvers() {

this.setThrowableResolver(InvalidSourceException.class, (exception, imperat, context) -> {
throw new UnsupportedOperationException("Couldn't find any source resolver for valueType `"
+ exception.getTargetType().getType().getTypeName() + "'");
+ exception.getTargetType().getTypeName() + "'");
});

this.setThrowableResolver(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import dev.velix.imperat.context.internal.CommandInputStream;
import dev.velix.imperat.exception.ImperatException;
import dev.velix.imperat.exception.SourceException;
import dev.velix.imperat.util.ImperatDebugger;
import dev.velix.imperat.util.TypeUtility;
import dev.velix.imperat.util.TypeWrap;
import org.jetbrains.annotations.NotNull;
Expand Down Expand Up @@ -35,7 +34,7 @@ public ParameterEnum(TypeWrap<Enum<?>> typeWrap) {
try {
assert raw.isPresent();
return Enum.valueOf((Class<? extends Enum>) enumType, raw.get());
} catch (EnumConstantNotPresentException ex) {
} catch (IllegalArgumentException | EnumConstantNotPresentException ex) {
throw new SourceException("Invalid " + enumType.getTypeName() + " '" + raw + "'");
}
}
Expand All @@ -46,10 +45,10 @@ public boolean matchesInput(String input, CommandParameter<S> parameter) {
if (!TypeWrap.of(type).isSubtypeOf(Enum.class)) {
return true;
}
ImperatDebugger.debug("type-enum-name= " + type.getTypeName());
//ImperatDebugger.debug("type-enum-name= " + type.getTypeName());
Enum.valueOf((Class<? extends Enum>) type, input);
return true;
} catch (EnumConstantNotPresentException ex) {
} catch (IllegalArgumentException | EnumConstantNotPresentException ex) {
return false;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import org.jetbrains.annotations.NotNull;

import java.util.Collection;
import java.util.Collections;
import java.util.concurrent.CompletableFuture;

/**
Expand Down Expand Up @@ -55,8 +56,12 @@ public final CompletableFuture<Collection<String>> autoComplete(

SuggestionContext<S> context = dispatcher.getContextFactory()
.createSuggestionContext(sender, command, queue, argToComplete);

return autoComplete(dispatcher, context);
//ImperatDebugger.debug("auto completing !");
return autoComplete(dispatcher, context)
.exceptionally((ex) -> {
dispatcher.handleThrowable(ex, context, AutoCompleter.class, "autoComplete(dispatcher, sender, args)");
return Collections.emptyList();
});
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,15 @@ public void result(Result result) {
public void visualize() {
ImperatDebugger.debug("Result => " + result.name());
StringBuilder builder = new StringBuilder();
int size = parameters.size();

int i = 0;
for (var node : parameters) {
builder.append(node.format()).append(" -> ");
builder.append(node.format());
if (i != size - 1) {
builder.append(" -> ");
}
i++;
}
ImperatDebugger.debug(builder.toString());
}
Expand Down
21 changes: 15 additions & 6 deletions core/src/main/java/dev/velix/imperat/command/tree/CommandTree.java
Original file line number Diff line number Diff line change
Expand Up @@ -110,17 +110,22 @@ private CompletableFuture<Collection<String>> collectNodeCompletions(
String raw = context.arguments().getOr(depth, "");
assert raw != null;

if (
(!raw.isBlank() || !raw.isEmpty()) && !child.matchesInput(raw)
|| (!root.data.isIgnoringACPerms() && !imperat.getPermissionResolver()
.hasPermission(context.source(), child.data.permission()))
) {
if (raw.isEmpty() || raw.isBlank()) {
return CompletableFuture.completedFuture(results);
}

boolean hasNoPermission = (!root.data.isIgnoringACPerms() && !imperat.getPermissionResolver()
.hasPermission(context.source(), child.data.permission()));

if (hasNoPermission) {
//ImperatDebugger.debug("Ending tab completion quickly");
return CompletableFuture.completedFuture(results);
}

if (depth == maxDepth) {
//we reached the arg we want to complete, let's complete it using our current node
//COMPLETE DIRECTLY
//ImperatDebugger.debug("Adding childs results");
return addChildResults(imperat, context, child);
} else {
if (child.data.isFlag() && !child.data.asFlagParameter().isSwitch()) {
Expand All @@ -143,7 +148,11 @@ private CompletableFuture<Collection<String>> addChildResults(
ParameterNode<S, ?> node
) {
SuggestionResolver<S> resolver = imperat.getParameterSuggestionResolver(node.data);
return resolver.asyncAutoComplete(context, node.data);
return resolver.asyncAutoComplete(context, node.data)
.thenApply((results) -> {
results.removeIf((entry) -> !node.matchesInput(entry));
return results;
});
}


Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package dev.velix.imperat.command.tree;

import dev.velix.imperat.context.Source;
import dev.velix.imperat.util.ImperatDebugger;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nullable;

Expand All @@ -23,7 +22,7 @@ public void visualize() {
if (tree == null) return;
StringBuilder builder = new StringBuilder();
visualizeNode(tree.root, builder, 0);
ImperatDebugger.debug(builder.toString());
//ImperatDebugger.debug(builder.toString());
}

private void visualizeNode(ParameterNode<S, ?> node, StringBuilder builder, int depth) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ default String collectBeforeFirst(char c) {
break;
}
builder.append(current);
skipLetter();
}
return builder.toString();
}
Expand Down

0 comments on commit b807d56

Please sign in to comment.