Refactor confirmation

This commit is contained in:
Jesse Boyd
2019-11-21 06:50:37 +00:00
parent 444aa0dda7
commit 52a502a1c6
22 changed files with 782 additions and 575 deletions

View File

@ -19,9 +19,6 @@
package com.sk89q.worldedit.internal.command;
import static com.google.common.base.Preconditions.checkState;
import static java.util.stream.Collectors.toList;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.sk89q.worldedit.extension.platform.Actor;
@ -32,13 +29,6 @@ import com.sk89q.worldedit.util.formatting.text.TextComponent;
import com.sk89q.worldedit.util.formatting.text.event.ClickEvent;
import com.sk89q.worldedit.util.formatting.text.format.TextColor;
import com.sk89q.worldedit.util.formatting.text.format.TextDecoration;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import org.enginehub.piston.Command;
import org.enginehub.piston.CommandParameters;
import org.enginehub.piston.NoInputCommandParameters;
@ -47,19 +37,30 @@ import org.enginehub.piston.inject.InjectedValueAccess;
import org.enginehub.piston.inject.Key;
import org.enginehub.piston.part.SubCommandPart;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import static com.google.common.base.Preconditions.checkState;
import static java.util.stream.Collectors.toList;
public class CommandUtil {
private static final Component DEPRECATION_MARKER = TextComponent.of("This command is deprecated.");
private static Component makeDeprecatedFooter(String reason, Component newCommand) {
return TextComponent.builder()
.append(DEPRECATION_MARKER)
.append(" " + reason + ".")
.append(TextComponent.newline())
.append(TextComponent.of("Use ", TextColor.GOLD, TextDecoration.ITALIC))
.append(newCommand)
.append(TextComponent.of(" instead.", TextColor.GOLD, TextDecoration.ITALIC))
.build();
.append(DEPRECATION_MARKER)
.append(" " + reason + ".")
.append(TextComponent.newline())
.append(TextComponent.of("Use ", TextColor.GOLD, TextDecoration.ITALIC))
.append(newCommand)
.append(TextComponent.of(" instead.", TextColor.GOLD, TextDecoration.ITALIC))
.build();
}
public interface NewCommandGenerator {
@ -71,45 +72,45 @@ public class CommandUtil {
public static Command deprecate(Command command, String reason,
NewCommandGenerator newCommandGenerator) {
Component deprecatedWarning = makeDeprecatedFooter(
reason,
newCommandSuggestion(newCommandGenerator,
NoInputCommandParameters.builder().build(),
command)
reason,
newCommandSuggestion(newCommandGenerator,
NoInputCommandParameters.builder().build(),
command)
);
return command.toBuilder()
.action(parameters ->
deprecatedCommandWarning(parameters, command, reason, newCommandGenerator))
.footer(command.getFooter()
.map(existingFooter -> existingFooter
.append(TextComponent.newline()).append(deprecatedWarning))
.orElse(deprecatedWarning))
.build();
.action(parameters ->
deprecatedCommandWarning(parameters, command, reason, newCommandGenerator))
.footer(command.getFooter()
.map(existingFooter -> existingFooter
.append(TextComponent.newline()).append(deprecatedWarning))
.orElse(deprecatedWarning))
.build();
}
public static Optional<Component> footerWithoutDeprecation(Command command) {
return command.getFooter()
.filter(footer -> anyComponent(footer, Predicate.isEqual(DEPRECATION_MARKER)))
.map(footer -> Optional.of(
replaceDeprecation(footer)
))
.orElseGet(command::getFooter);
.filter(footer -> anyComponent(footer, Predicate.isEqual(DEPRECATION_MARKER)))
.map(footer -> Optional.of(
replaceDeprecation(footer)
))
.orElseGet(command::getFooter);
}
public static Optional<Component> deprecationWarning(Command command) {
return command.getFooter()
.map(CommandUtil::extractDeprecation)
.orElseGet(command::getFooter);
.map(CommandUtil::extractDeprecation)
.orElseGet(command::getFooter);
}
public static boolean isDeprecated(Command command) {
return command.getFooter()
.filter(footer -> anyComponent(footer, Predicate.isEqual(DEPRECATION_MARKER)))
.isPresent();
.filter(footer -> anyComponent(footer, Predicate.isEqual(DEPRECATION_MARKER)))
.isPresent();
}
private static boolean anyComponent(Component component, Predicate<Component> test) {
return test.test(component) || component.children().stream()
.anyMatch(x -> anyComponent(x, test));
.anyMatch(x -> anyComponent(x, test));
}
private static Component replaceDeprecation(Component component) {
@ -117,9 +118,9 @@ public class CommandUtil {
return TextComponent.empty();
}
return component.children(
component.children().stream()
.map(CommandUtil::replaceDeprecation)
.collect(toList())
component.children().stream()
.map(CommandUtil::replaceDeprecation)
.collect(toList())
);
}
@ -128,26 +129,26 @@ public class CommandUtil {
return Optional.of(component);
}
return component.children().stream()
.map(CommandUtil::extractDeprecation)
.filter(Optional::isPresent)
.map(Optional::get)
.findAny();
.map(CommandUtil::extractDeprecation)
.filter(Optional::isPresent)
.map(Optional::get)
.findAny();
}
private static Object deprecatedCommandWarning(
CommandParameters parameters,
Command command,
String reason,
NewCommandGenerator generator
CommandParameters parameters,
Command command,
String reason,
NewCommandGenerator generator
) throws Exception {
parameters.injectedValue(Key.of(Actor.class))
.ifPresent(actor -> {
Component suggestion = newCommandSuggestion(generator, parameters, command);
actor.print(TextComponent.of(reason + ". Please use ", TextColor.GOLD)
.append(suggestion)
.append(TextComponent.of(" instead."))
);
});
.ifPresent(actor -> {
Component suggestion = newCommandSuggestion(generator, parameters, command);
actor.print(TextComponent.of(reason + ". Please use ", TextColor.GOLD)
.append(suggestion)
.append(TextComponent.of(" instead."))
);
});
return command.getAction().run(parameters);
}
@ -156,15 +157,15 @@ public class CommandUtil {
Command command) {
String suggestedCommand = generator.newCommand(command, parameters);
return TextComponent.of(suggestedCommand)
.decoration(TextDecoration.UNDERLINED, true)
.clickEvent(ClickEvent.suggestCommand(suggestedCommand));
.decoration(TextDecoration.UNDERLINED, true)
.clickEvent(ClickEvent.suggestCommand(suggestedCommand));
}
public static Map<String, Command> getSubCommands(Command currentCommand) {
return currentCommand.getParts().stream()
.filter(p -> p instanceof SubCommandPart)
.flatMap(p -> ((SubCommandPart) p).getCommands().stream())
.collect(Collectors.toMap(Command::getName, Function.identity()));
.filter(p -> p instanceof SubCommandPart)
.flatMap(p -> ((SubCommandPart) p).getCommands().stream())
.collect(Collectors.toMap(Command::getName, Function.identity()));
}
private static String clean(String input) {
@ -172,7 +173,7 @@ public class CommandUtil {
}
private static final Comparator<Command> BY_CLEAN_NAME =
Comparator.comparing(c -> clean(c.getName()));
Comparator.comparing(c -> clean(c.getName()));
public static Comparator<Command> byCleanName() {
return BY_CLEAN_NAME;
@ -183,15 +184,15 @@ public class CommandUtil {
*/
public static List<String> fixSuggestions(String arguments, List<Substring> suggestions) {
Substring lastArg = Iterables.getLast(
CommandArgParser.spaceSplit(arguments)
CommandArgParser.spaceSplit(arguments)
);
return suggestions.stream()
// Re-map suggestions to only operate on the last non-quoted word
.map(suggestion -> onlyOnLastQuotedWord(lastArg, suggestion))
.map(suggestion -> suggestLast(lastArg, suggestion))
.filter(Optional::isPresent)
.map(Optional::get)
.collect(toList());
// Re-map suggestions to only operate on the last non-quoted word
.map(suggestion -> onlyOnLastQuotedWord(lastArg, suggestion))
.map(suggestion -> suggestLast(lastArg, suggestion))
.filter(Optional::isPresent)
.map(Optional::get)
.collect(toList());
}
private static Substring onlyOnLastQuotedWord(Substring lastArg, Substring suggestion) {
@ -227,7 +228,7 @@ public class CommandUtil {
return Optional.empty();
}
checkState(end <= builder.length(),
"Suggestion ends too late, last=%s, suggestion=", last, suggestion);
"Suggestion ends too late, last=%s, suggestion=", last, suggestion);
builder.replace(start, end, suggestion.getSubstring());
return Optional.of(builder.toString());
}
@ -258,10 +259,10 @@ public class CommandUtil {
public static <T> T requireIV(Key<T> type, String name, InjectedValueAccess injectedValueAccess) {
return injectedValueAccess.injectedValue(type).orElseThrow(() ->
new IllegalStateException("No injected value for " + name + " (type " + type + ")")
new IllegalStateException("No injected value for " + name + " (type " + type + ")")
);
}
private CommandUtil() {
}
}
}

View File

@ -0,0 +1,47 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.internal.command;
import com.sk89q.worldedit.command.util.annotation.Confirm;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.util.formatting.text.TextComponent;
import org.enginehub.piston.CommandParameters;
import org.enginehub.piston.exception.StopExecutionException;
import org.enginehub.piston.gen.CommandCallListener;
import org.enginehub.piston.inject.Key;
import java.lang.reflect.Method;
/**
* Logs called commands to a logger.
*/
public class ConfirmHandler implements CommandCallListener {
@Override
public void beforeCall(Method method, CommandParameters parameters) {
Confirm confirmAnnotation = method.getAnnotation(Confirm.class);
if (confirmAnnotation == null) {
return;
}
Actor actor = parameters.injectedValue(Key.of(Actor.class)).get();
if (!confirmAnnotation.value().passes(actor, parameters, 1)) {
throw new StopExecutionException(TextComponent.empty());
}
}
}

View File

@ -0,0 +1,19 @@
package com.sk89q.worldedit.internal.command;
import org.enginehub.piston.CommandParameters;
import org.enginehub.piston.gen.CommandCallListener;
import org.enginehub.piston.inject.InjectedValueAccess;
import org.enginehub.piston.inject.InjectedValueStore;
import org.enginehub.piston.inject.Key;
import org.enginehub.piston.util.ValueProvider;
import java.lang.reflect.Method;
import java.util.Optional;
public class MethodInjector implements CommandCallListener {
@Override
public void beforeCall(Method commandMethod, CommandParameters parameters) {
InjectedValueStore store = parameters.injectedValue(Key.of(InjectedValueStore.class)).get();
store.injectValue(Key.of(Method.class), ValueProvider.constant(commandMethod));
}
}