Attempt to fix space tab completion.

This commit is contained in:
Magnus Ulf 2015-05-14 09:48:53 +02:00 committed by Olof Larsson
parent 0bc46a0818
commit 78e272cdb4
2 changed files with 60 additions and 43 deletions

View File

@ -1,14 +1,14 @@
package com.massivecraft.massivecore.cmd.arg; package com.massivecraft.massivecore.cmd.arg;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
import java.util.ListIterator;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import com.google.common.collect.Lists;
import com.massivecraft.massivecore.MassiveException; import com.massivecraft.massivecore.MassiveException;
import com.massivecraft.massivecore.util.Txt; import com.massivecraft.massivecore.util.Txt;
@ -95,7 +95,7 @@ public abstract class ARAbstract<T> implements AR<T>
// Because spaces and tab completion desn't go well together. // Because spaces and tab completion desn't go well together.
// In the future we might be able to do something better, // In the future we might be able to do something better,
// but MineCraft has its limitations. // but MineCraft has its limitations.
ret = prepareForSpaces(ret); ret = prepareForSpaces(ret, arg);
return ret; return ret;
} }
@ -104,17 +104,18 @@ public abstract class ARAbstract<T> implements AR<T>
// PRIVATE: TAB COMPLETE CALCULATIONS // PRIVATE: TAB COMPLETE CALCULATIONS
// -------------------------------------------- // // -------------------------------------------- //
public static List<String> prepareForSpaces(List<String> suggestions) public static List<String> prepareForSpaces(List<String> suggestions, String arg)
{ {
List<List<String>> suggestionParts = getParts(suggestions); cleanSuggestions(suggestions);
// This will get the common prefix for all passed in 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 somethings with spaces
// if we know they all start with the same value, // if we know they all start with the same value,
// so we don't have to replace all of it. // so we don't have to replace all of it.
List<String> prefix = getPrefix(suggestionParts); final String prefix = getPrefix(suggestions);
// This is all the suggetions without the common prefix. // This is all the suggetions without the common prefix.
List<String> ret = withoutPreAndSuffix(suggestionParts, prefix); List<String> ret = withoutPreAndSuffix(suggestions, prefix);
// If it isn't empty and there is a prefix... // If it isn't empty and there is a prefix...
if ( ! ret.isEmpty() && ! prefix.isEmpty()) if ( ! ret.isEmpty() && ! prefix.isEmpty())
{ {
@ -122,36 +123,43 @@ public abstract class ARAbstract<T> implements AR<T>
// That prefix is not removed automatically, // That prefix is not removed automatically,
// due to how tab completion works. // due to how tab completion works.
final String current = ret.get(0); final String current = ret.get(0);
final String prefixStr = Txt.implode(prefix, " "); String result = prefix;
String result = prefixStr; if ( ! current.isEmpty())
if ( ! current.isEmpty()) result += " " + current; {
if (result.charAt(result.length()-1) != ' ') result += ' ';
result += current;
}
int unwantedPrefixLength = arg.lastIndexOf(' ');
if (unwantedPrefixLength != -1)
{
unwantedPrefixLength++;
result = result.substring(unwantedPrefixLength);
}
ret.set(0, result); ret.set(0, result);
} }
return ret;
}
// This things splits up the arguments at spaces.
private static List<List<String>> getParts(List<String> list)
{
List<List<String>> ret = Lists.newArrayList();
for (String str : list)
{
if (str == null) continue;
if (str.isEmpty()) continue;
ret.add(Arrays.asList(str.split("\\s+")));
}
return ret; return ret;
} }
private static List<String> withoutPreAndSuffix(List<List<String>> suggestionParts, List<String> prefix) private static void cleanSuggestions(List<String> suggestions)
{ {
List<String> ret = new ArrayList<String>(suggestionParts.size()); for (ListIterator<String> it = suggestions.listIterator(); it.hasNext();)
{
String suggestion = it.next();
if (suggestion == null) it.remove();
else if (suggestion.isEmpty()) it.remove();
else it.set(suggestion.toLowerCase());
}
}
private static List<String> withoutPreAndSuffix(List<String> suggestions, String prefix)
{
LinkedHashSet<String> ret = new LinkedHashSet<String>(suggestions.size());
boolean includesPrefix = false; // Sometimes a suggestion is equal to the prefix. boolean includesPrefix = false; // Sometimes a suggestion is equal to the prefix.
for (List<String> suggestion : suggestionParts) for (String suggestion : suggestions)
{ {
if (suggestion.equals(prefix) && !includesPrefix) if (suggestion.equals(prefix) && !includesPrefix)
{ {
@ -162,42 +170,51 @@ public abstract class ARAbstract<T> implements AR<T>
// We remove the prefix because we only want that once. // We remove the prefix because we only want that once.
// But we can't keep things after the first part either // But we can't keep things after the first part either
// because of spaces and stuff. // because of spaces and stuff.
if (suggestion.size() <= prefix.size()) continue; if (suggestion.length() <= prefix.length()) continue;
ret.add(suggestion.get(prefix.size())); int lastSpace = prefix.indexOf(' ', prefix.length());
int lastIndex = lastSpace != -1 ? lastSpace : suggestion.length();
ret.add(suggestion.substring(prefix.length(), lastIndex));
} }
return ret; return new ArrayList<String>(ret);
} }
private static List<String> getPrefix(List<List<String>> suggestionParts) private static String getPrefix(List<String> suggestions)
{ {
List<String> prefix = null; String prefix = null;
for (List<String> suggestion : suggestionParts) for (String suggestion : suggestions)
{ {
prefix = getOkay(prefix, suggestion); prefix = getOkay(prefix, suggestion);
} }
return prefix; if (prefix == null) return "";
int lastSpace = prefix.lastIndexOf(" ");
if (lastSpace == -1) return "";
return prefix.substring(0, lastSpace+1);
} }
// This method return a new array only including // This method return a new string only including
// the first parts that are equal. // the first characters that are equal.
private static List<String> getOkay(List<String> original, List<String> compared) private static String getOkay(String original, String compared)
{ {
if (original == null) return compared; if (original == null) return compared;
final int size = Math.min(original.length(), compared.length());
final int size = Math.min(original.size(), compared.size()); StringBuilder ret = new StringBuilder();
List<String> ret = new ArrayList<String>(size);
for (int i = 0; i < size; i++) for (int i = 0; i < size; i++)
{ {
if (compared.get(i) == null || original.get(i) == null) break; if (Character.toLowerCase(compared.charAt(i)) != Character.toLowerCase(original.charAt(i))) break;
if ( ! compared.get(i).equals(original.get(i))) break; ret.append(compared.charAt(i));
ret.add(original.get(i));
} }
return ret; if (ret.length() == 0) return "";
int lastSpace = ret.lastIndexOf(" ");
if (lastSpace == -1) return "";
return ret.toString();
} }
} }