package fr.pandacube.util.commands; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.function.Predicate; import java.util.stream.Collectors; import java.util.stream.IntStream; import java.util.stream.Stream; @FunctionalInterface public interface Suggestions { public abstract List getSuggestions(S sender, int tokenIndex, String token, String[] args); public static Predicate filter(String token) { return suggestion -> suggestion.toLowerCase().startsWith(token.toLowerCase()); } /** * Filter the provided {@link Stream} of string according to the provided token, using the filter returned by {@link #filter(String)}, * then returns the strings collected into a {@link List}. * * This methods consume the provided stream, so will not be usable anymore. */ public static List collectFilteredStream(Stream stream, String token) { return stream.filter(filter(token)).sorted().collect(Collectors.toList()); } public static Suggestions empty() { return (s, ti, t, a) -> Collections.emptyList(); } public static Suggestions fromCollection(Collection suggestions) { return (s, ti, token, a) -> collectFilteredStream(suggestions.stream(), token); } public static Suggestions fromArray(String... suggestions) { return (s, ti, token, a) -> collectFilteredStream(Arrays.stream(suggestions), token); } public static , S> Suggestions fromEnum(Class enumClass) { return fromEnumValues(enumClass.getEnumConstants()); } public static , S> Suggestions fromEnum(Class enumClass, boolean lowerCase) { return fromEnumValues(lowerCase, enumClass.getEnumConstants()); } @SafeVarargs public static , S> Suggestions fromEnumValues(E... enumValues) { return fromEnumValues(false, enumValues); } @SafeVarargs public static , S> Suggestions fromEnumValues(boolean lowerCase, E... enumValues) { return (s, ti, token, a) -> { Stream st = Arrays.stream(enumValues).map(Enum::name); if (lowerCase) st = st.map(String::toLowerCase); return collectFilteredStream(st, token); }; } public static Suggestions fromIntRange(int min, int max) { return (s, ti, token, a) -> { return collectFilteredStream(IntStream.range(min, max + 1).mapToObj(Integer::toString), token); }; } /** * Create a {@link Suggestions} that support greedy strings argument using the suggestion from this {@link Suggestions}. * @param args all the arguments currently in the buffer * @param index the index of the first argument of the greedy string argument * @return */ public default Suggestions greedyString(int index) { return (s, ti, token, args) -> { if (ti < index) return Collections.emptyList(); String gToken = AbstractCommand.getLastParams(args, index); String[] splitGToken = gToken.split(" ", -1); int currentTokenPosition = splitGToken.length - 1; String[] prevWordsGToken = Arrays.copyOf(splitGToken, currentTokenPosition); String[] argsWithMergedGreedyToken = Arrays.copyOf(args, index + 1); argsWithMergedGreedyToken[index] = gToken; List currentTokenProposal = new ArrayList<>(); for (String suggestion : getSuggestions(s, index, gToken, argsWithMergedGreedyToken)) { String[] splitSuggestion = suggestion.split(" ", -1); if (splitSuggestion.length <= currentTokenPosition) continue; if (!Arrays.equals(Arrays.copyOf(splitGToken, currentTokenPosition), prevWordsGToken)) continue; if (splitSuggestion[currentTokenPosition].isEmpty()) continue; currentTokenProposal.add(splitSuggestion[currentTokenPosition]); } return currentTokenProposal; }; } }