From 98ba8cda53c2e02e68f4604c67d99fff6fecb519 Mon Sep 17 00:00:00 2001 From: Olof Larsson Date: Mon, 3 Aug 2015 11:52:39 +0200 Subject: [PATCH] Case sensitive tab completion. --- .../massivecore/cmd/arg/ARAbstract.java | 116 ++++++++++-------- .../massivecraft/massivecore/util/Txt.java | 7 +- 2 files changed, 68 insertions(+), 55 deletions(-) diff --git a/src/com/massivecraft/massivecore/cmd/arg/ARAbstract.java b/src/com/massivecraft/massivecore/cmd/arg/ARAbstract.java index 6972a452..f0faebe3 100644 --- a/src/com/massivecraft/massivecore/cmd/arg/ARAbstract.java +++ b/src/com/massivecraft/massivecore/cmd/arg/ARAbstract.java @@ -85,16 +85,25 @@ public abstract class ARAbstract implements AR @Override public List getTabListFiltered(CommandSender sender, String arg) { - // Filter them to start with what the user typed in. + // Get the raw tab list. Collection raw = this.getTabList(sender, arg); + + // Handle null case. if (raw == null || raw.isEmpty()) return Collections.emptyList(); + // Only keep the suggestions that starts with what the user already typed in. + // This is the first basic step of tab completion. + // "Ca" can complete into "Cayorion". + // "Ma" can complete into "Madus" + // "Ca" can not complete into "Madus" because it does not start with ignore case. List ret = Txt.getStartsWithIgnoreCase(raw, arg); + // Initial simple cleanup of suggestions. + cleanSuggestions(ret); + // Here we do a lot of things related to spaces. - // Because spaces and tab completion desn't go well together. - // In the future we might be able to do something better, - // but MineCraft has its limitations. + // Because spaces and tab completion doesn't go well together. + // In the future we might be able to do something better, but Minecraft has its limitations. ret = prepareForSpaces(ret, arg); return ret; @@ -104,17 +113,30 @@ public abstract class ARAbstract implements AR // PRIVATE: TAB COMPLETE CALCULATIONS // -------------------------------------------- // + // This method performs an initial cleanup of suggestions. + // Currently we just throw away nulls and empty strings. + private static void cleanSuggestions(List suggestions) + { + ListIterator iter = suggestions.listIterator(); + while (iter.hasNext()) + { + String suggestion = iter.next(); + if (suggestion == null || suggestion.isEmpty()) + { + iter.remove(); + } + } + } + public static List prepareForSpaces(List suggestions, String arg) { - cleanSuggestions(suggestions); - // This will get the common prefix for all passed in suggestions. - // This will allow us to tab complete somethings with spaces + // This will allow us to tab complete some things with spaces // if we know they all start with the same value, // so we don't have to replace all of it. final String prefix = getPrefix(suggestions); - // This is all the suggetions without the common prefix. + // This is all the suggestions without the common prefix. List ret = withoutPreAndSuffix(suggestions, prefix); // If it isn't empty and there is a prefix... if ( ! ret.isEmpty() && ! prefix.isEmpty()) @@ -130,7 +152,7 @@ public abstract class ARAbstract implements AR result += current; } - int unwantedPrefixLength = arg.lastIndexOf(' '); + int unwantedPrefixLength = arg.lastIndexOf(' '); if (unwantedPrefixLength != -1) { unwantedPrefixLength++; @@ -142,15 +164,41 @@ public abstract class ARAbstract implements AR return ret; } - private static void cleanSuggestions(List suggestions) + private static String getPrefix(List suggestions) { - for (ListIterator it = suggestions.listIterator(); it.hasNext();) + String prefix = null; + + for (String suggestion : suggestions) { - String suggestion = it.next(); - if (suggestion == null) it.remove(); - else if (suggestion.isEmpty()) it.remove(); - else it.set(suggestion.toLowerCase()); + prefix = getOkay(prefix, suggestion); } + + if (prefix == null) return ""; + int lastSpace = prefix.lastIndexOf(" "); + if (lastSpace == -1) return ""; + + return prefix.substring(0, lastSpace + 1); + } + + // This method return a new string only including the first characters that are equal. + private static String getOkay(String original, String compared) + { + if (original == null) return compared; + final int size = Math.min(original.length(), compared.length()); + StringBuilder ret = new StringBuilder(); + + for (int i = 0; i < size; i++) + { + if (Character.toLowerCase(compared.charAt(i)) != Character.toLowerCase(original.charAt(i))) break; + ret.append(compared.charAt(i)); + } + + if (ret.length() == 0) return ""; + + int lastSpace = ret.lastIndexOf(" "); + if (lastSpace == -1) return ""; + + return ret.toString(); } private static List withoutPreAndSuffix(List suggestions, String prefix) @@ -177,42 +225,4 @@ public abstract class ARAbstract implements AR return new ArrayList(ret); } - private static String getPrefix(List suggestions) - { - String prefix = null; - - for (String suggestion : suggestions) - { - prefix = getOkay(prefix, suggestion); - } - - if (prefix == null) return ""; - int lastSpace = prefix.lastIndexOf(" "); - if (lastSpace == -1) return ""; - - return prefix.substring(0, lastSpace+1); - } - - // This method return a new string only including - // the first characters that are equal. - private static String getOkay(String original, String compared) - { - if (original == null) return compared; - final int size = Math.min(original.length(), compared.length()); - StringBuilder ret = new StringBuilder(); - - for (int i = 0; i < size; i++) - { - if (Character.toLowerCase(compared.charAt(i)) != Character.toLowerCase(original.charAt(i))) break; - ret.append(compared.charAt(i)); - } - - if (ret.length() == 0) return ""; - - int lastSpace = ret.lastIndexOf(" "); - if (lastSpace == -1) return ""; - - return ret.toString(); - } - } diff --git a/src/com/massivecraft/massivecore/util/Txt.java b/src/com/massivecraft/massivecore/util/Txt.java index e4389385..0dcb0ac8 100644 --- a/src/com/massivecraft/massivecore/util/Txt.java +++ b/src/com/massivecraft/massivecore/util/Txt.java @@ -582,16 +582,19 @@ public class Txt // FILTER // -------------------------------------------- // - public static List getFiltered(Collection elements, Predictate predictate) + public static List getFiltered(Iterable elements, Predictate predictate) { + // Create Ret List ret = new ArrayList(); + // Fill Ret for (T element : elements) { if ( ! predictate.apply(element)) continue; ret.add(element); } + // Return Ret return ret; } @@ -600,7 +603,7 @@ public class Txt return getFiltered(Arrays.asList(elements), predictate); } - public static List getStartsWithIgnoreCase(Collection elements, String prefix) + public static List getStartsWithIgnoreCase(Iterable elements, String prefix) { return getFiltered(elements, PredictateStartsWithIgnoreCase.get(prefix)); }