Refactor Tab Suggestions code
This commit is contained in:
parent
0f8f190428
commit
057f5e8cfa
@ -29,4 +29,12 @@ public class StringUtil {
|
|||||||
int size = strings == null ? 0 : strings.size();
|
int size = strings == null ? 0 : strings.size();
|
||||||
return size == 0 ? "" : size == 1 ? strings.get(0) : String.join(sep1, strings.subList(0, --size)) + sepFinal + strings.get(size);
|
return size == 0 ? "" : size == 1 ? strings.get(0) : String.join(sep1, strings.subList(0, --size)) + sepFinal + strings.get(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static String repeat(String base, int count) {
|
||||||
|
return new String(new char[count]).replace("\0", base);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
117
src/main/java/fr/pandacube/util/commands/Suggestions.java
Normal file
117
src/main/java/fr/pandacube/util/commands/Suggestions.java
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
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.Stream;
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface Suggestions<S> {
|
||||||
|
|
||||||
|
|
||||||
|
public abstract List<String> getSuggestions(S sender, int tokenIndex, String token, String[] args);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static Predicate<String> 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<String> collectFilteredStream(Stream<String> stream, String token) {
|
||||||
|
return stream.filter(filter(token)).sorted().collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static <S> Suggestions<S> empty() { return (s, ti, t, a) -> Collections.emptyList(); }
|
||||||
|
|
||||||
|
|
||||||
|
public static <S> Suggestions<S> fromCollection(Collection<String> suggestions) {
|
||||||
|
return (s, ti, token, a) -> collectFilteredStream(suggestions.stream(), token);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <S> Suggestions<S> fromArray(String... suggestions) {
|
||||||
|
return (s, ti, token, a) -> collectFilteredStream(Arrays.stream(suggestions), token);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static <E extends Enum<E>, S> Suggestions<S> fromEnum(Class<E> enumClass) {
|
||||||
|
return fromEnumValues(enumClass.getEnumConstants());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <E extends Enum<E>, S> Suggestions<S> fromEnum(Class<E> enumClass, boolean lowerCase) {
|
||||||
|
return fromEnumValues(lowerCase, enumClass.getEnumConstants());
|
||||||
|
}
|
||||||
|
|
||||||
|
@SafeVarargs
|
||||||
|
public static <E extends Enum<E>, S> Suggestions<S> fromEnumValues(E... enumValues) {
|
||||||
|
return fromEnumValues(false, enumValues);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SafeVarargs
|
||||||
|
public static <E extends Enum<E>, S> Suggestions<S> fromEnumValues(boolean lowerCase, E... enumValues) {
|
||||||
|
return (s, ti, token, a) -> {
|
||||||
|
Stream<String> st = Arrays.stream(enumValues).map(Enum::name);
|
||||||
|
if (lowerCase)
|
||||||
|
st = st.map(String::toLowerCase);
|
||||||
|
return collectFilteredStream(st, 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<S> 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<String> 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;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -1,87 +0,0 @@
|
|||||||
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 TabProposal {
|
|
||||||
|
|
||||||
|
|
||||||
public abstract List<String> getProposal(String token);
|
|
||||||
|
|
||||||
|
|
||||||
public static Predicate<String> filter(String token) {
|
|
||||||
return (proposal) -> proposal.toLowerCase().startsWith(token.toLowerCase());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List<String> filterStream(Stream<String> stream, String token) {
|
|
||||||
return stream.filter(filter(token)).sorted().collect(Collectors.toList());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public static TabProposal empty() { return t -> Collections.emptyList(); }
|
|
||||||
|
|
||||||
|
|
||||||
public static <E extends Enum<E>> TabProposal fromEnum(Class<E> enumClass) {
|
|
||||||
return fromEnumValues(enumClass.getEnumConstants());
|
|
||||||
}
|
|
||||||
|
|
||||||
@SafeVarargs
|
|
||||||
public static <E extends Enum<E>> TabProposal fromEnumValues(E... enumValues) {
|
|
||||||
return fromStream(Arrays.stream(enumValues).map(Enum::name));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static TabProposal fromCollection(Collection<String> proposals) {
|
|
||||||
return fromStream(proposals.stream());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static TabProposal fromIntRange(int startIncluded, int endIncluded) {
|
|
||||||
return fromStream(IntStream.rangeClosed(startIncluded, endIncluded).mapToObj(Integer::toString));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static TabProposal fromStream(Stream<String> proposals) {
|
|
||||||
return t -> filterStream(proposals, t);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Allow tab completion to supply proposal from multi-args (arguments with space,
|
|
||||||
* generally the last argument of a command) parameters
|
|
||||||
* @param args all the arguments currently in the buffer
|
|
||||||
* @param index the index of the first argument of the multi-args parameter
|
|
||||||
* @param proposals all possible proposals for the multi-args parameter
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public static TabProposal withMultiArgsLastParam(String[] args, int index, Collection<String> proposals) {
|
|
||||||
String lastParamToken = AbstractCommand.getLastParams(args, index);
|
|
||||||
String[] splittedToken = lastParamToken.split(" ", -1);
|
|
||||||
int currentTokenPosition = splittedToken.length - 1;
|
|
||||||
String[] previousTokens = Arrays.copyOf(splittedToken, currentTokenPosition);
|
|
||||||
|
|
||||||
return token -> {
|
|
||||||
List<String> currentTokenProposal = new ArrayList<>();
|
|
||||||
for (String p : proposals) {
|
|
||||||
String[] splittedProposal = p.split(" ", -1);
|
|
||||||
if (splittedProposal.length <= currentTokenPosition)
|
|
||||||
continue;
|
|
||||||
if (!Arrays.equals(Arrays.copyOf(splittedToken, currentTokenPosition), previousTokens))
|
|
||||||
continue;
|
|
||||||
if (splittedProposal[currentTokenPosition].isEmpty())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (filter(token).test(splittedProposal[currentTokenPosition]))
|
|
||||||
currentTokenProposal.add(splittedProposal[currentTokenPosition]);
|
|
||||||
}
|
|
||||||
return currentTokenProposal;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user