Match Bukkit tab completion behaviour

This commit is contained in:
samczsun 2017-01-17 18:15:43 -05:00 committed by cnr
parent cc9f28dfec
commit 8b1fe8302e
16 changed files with 189 additions and 215 deletions

View File

@ -4,9 +4,11 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.function.Consumer;
import java.util.Locale;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
@ -80,11 +82,31 @@ public abstract class CommandBase<PluginType extends MiniPlugin> implements ICom
}
@Override
public List<String> onTabComplete(CommandSender sender, String commandLabel, String[] args, boolean endsWithSpace)
public List<String> onTabComplete(CommandSender sender, String commandLabel, String[] args)
{
return null;
}
protected <T> List<String> getMatches(String start, Collection<T> possibleMatches, Function<T, String> toString)
{
List<String> matches = new ArrayList<String>();
for (T possibleMatch : possibleMatches)
{
String str = toString.apply(possibleMatch);
if (str.toLowerCase().startsWith(start.toLowerCase()))
matches.add(str);
}
return matches;
}
protected List<String> getMatches(String start, Stream<String> possibleMatches)
{
String lcase = start.toLowerCase(Locale.ENGLISH);
return possibleMatches.filter(str -> str.toLowerCase(Locale.ENGLISH).startsWith(lcase)).collect(Collectors.toList());
}
protected List<String> getMatches(String start, Collection<String> possibleMatches)
{
List<String> matches = new ArrayList<String>();
@ -113,33 +135,22 @@ public abstract class CommandBase<PluginType extends MiniPlugin> implements ICom
return matches;
}
protected List<String> tabCompletePlayerNames(CommandSender sender, String commandLabel, String[] args, boolean endsWithSpace)
protected List<String> tabCompletePlayerNames(CommandSender sender, String commandLabel, String[] args)
{
return tabCompletePlayerNames(sender, commandLabel, args, endsWithSpace, t -> true);
return tabCompletePlayerNames(sender, commandLabel, args, t -> true);
}
protected List<String> tabCompletePlayerNames(CommandSender sender, String commandLabel, String[] args, boolean endsWithSpace, Predicate<Player> filter)
protected List<String> tabCompletePlayerNames(CommandSender sender, String commandLabel, String[] args, Predicate<Player> filter)
{
if (sender instanceof Player)
{
if (args.length == 1)
{
if (!endsWithSpace)
{
return PlayerSelector.selectPlayers(
UtilLambda.and(
((Player) sender)::canSee,
player -> player.getName().toLowerCase().startsWith(args[0]),
filter
)
).stream().map(Player::getName).collect(Collectors.toList());
}
}
else if (args.length == 0)
{
String lcase = args[0].toLowerCase(Locale.ENGLISH);
return PlayerSelector.selectPlayers(
UtilLambda.and(
((Player) sender)::canSee,
player -> player.getName().toLowerCase(Locale.ENGLISH).startsWith(lcase),
filter
)
).stream().map(Player::getName).collect(Collectors.toList());

View File

@ -172,14 +172,12 @@ public class CommandCenter implements Listener, IPacketHandler
List<String> results = new ArrayList<>();
boolean endsWithSpace = message.endsWith(" ");
String commandName = message.substring(1);
String[] args = new String[0];
if (commandName.contains(" "))
{
String[] splits = commandName.split(" ");
String[] splits = commandName.split(" ", -1);
commandName = splits[0];
args = new String[splits.length - 1];
System.arraycopy(splits, 1, args, 0, args.length);
@ -187,7 +185,7 @@ public class CommandCenter implements Listener, IPacketHandler
// System.out.println("Handling tab complete for " + packetInfo.getPlayer().getName() + " " + commandName + " " + Arrays.toString(args) + " " + endsWithSpace);
if (endsWithSpace || args.length > 0)
if (args.length > 0)
{
// System.out.println("Path 1");
ICommand command = Commands.get(commandName.toLowerCase());
@ -197,7 +195,7 @@ public class CommandCenter implements Listener, IPacketHandler
if (ClientManager.Get(packetInfo.getPlayer()).GetRank().has(packetInfo.getPlayer(), command.GetRequiredRank(), command.GetSpecificRanks(), true)
|| UtilPlayer.isCommandAllowed(packetInfo.getPlayer(), commandName.toLowerCase()))
{
List<String> tmpres = command.onTabComplete(packetInfo.getPlayer(), commandName.toLowerCase(), args, endsWithSpace);
List<String> tmpres = command.onTabComplete(packetInfo.getPlayer(), commandName.toLowerCase(), args);
if (tmpres != null)
{
results.addAll(tmpres);

View File

@ -33,5 +33,5 @@ public interface ICommand extends Component
CommandCenter.Instance.removeCommand(this);
}
List<String> onTabComplete(CommandSender sender, String commandLabel, String[] args, boolean endsWithSpace);
List<String> onTabComplete(CommandSender sender, String commandLabel, String[] args);
}

View File

@ -1,10 +1,8 @@
package mineplex.core.command;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.Locale;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
@ -15,27 +13,27 @@ import mineplex.core.common.util.NautHashMap;
public abstract class MultiCommandBase<PluginType extends MiniPlugin> extends CommandBase<PluginType>
{
protected NautHashMap<String, ICommand> Commands;
private NautHashMap<String, ICommand> Commands;
public MultiCommandBase(PluginType plugin, Rank rank, String... aliases)
{
super(plugin, rank, aliases);
Commands = new NautHashMap<String, ICommand>();
Commands = new NautHashMap<>();
}
public MultiCommandBase(PluginType plugin, Rank rank, Rank[] specificRanks, String... aliases)
{
super(plugin, rank, specificRanks, aliases);
Commands = new NautHashMap<String, ICommand>();
Commands = new NautHashMap<>();
}
public void AddCommand(ICommand command)
{
for (String commandRoot : command.Aliases())
{
Commands.put(commandRoot, command);
Commands.put(commandRoot.toLowerCase(Locale.ENGLISH), command);
command.SetCommandCenter(_commandCenter);
}
}
@ -86,12 +84,11 @@ public abstract class MultiCommandBase<PluginType extends MiniPlugin> extends Co
}
@Override
public List<String> onTabComplete(CommandSender sender, String commandLabel, String[] args, boolean endsWithSpace)
public List<String> onTabComplete(CommandSender sender, String commandLabel, String[] args)
{
// System.out.println("Handling MultiCommandBase tab complete " + sender.getName() + " " + commandLabel + " " + Arrays.toString(args) + " " + endsWithSpace);
if (args.length > 1)
{
String commandName = args[0];
String commandName = args[0].toLowerCase(Locale.ENGLISH);
ICommand command = Commands.get(commandName);
@ -99,44 +96,12 @@ public abstract class MultiCommandBase<PluginType extends MiniPlugin> extends Co
{
String[] newArgs = new String[args.length - 1];
System.arraycopy(args, 1, newArgs, 0, newArgs.length);
return command.onTabComplete(sender, args[0], newArgs, endsWithSpace);
return command.onTabComplete(sender, args[0], newArgs);
}
}
else if (args.length == 1)
{
ICommand possibleCommand = Commands.get(args[0]);
// Tab completing a non-existant command, probably trying to tab-complete a command
if (possibleCommand == null)
{
if (!endsWithSpace)
{
Set<String> possibleMatches = new HashSet<>();
for (ICommand command : Commands.values())
{
possibleMatches.addAll(command.Aliases());
}
return getMatches(args[0], possibleMatches);
}
}
else if (endsWithSpace)
{
String[] newArgs = new String[args.length - 1];
System.arraycopy(args, 1, newArgs, 0, newArgs.length);
return possibleCommand.onTabComplete(sender, args[0], newArgs, endsWithSpace);
}
}
else
{
Set<String> possibleMatches = new HashSet<>();
for (ICommand command : Commands.values())
{
possibleMatches.addAll(command.Aliases());
}
return new ArrayList<>(possibleMatches);
return getMatches(args[0], Commands.values().stream().map(ICommand::Aliases).flatMap(Collection::stream));
}
return null;

View File

@ -1,10 +1,14 @@
package mineplex.core.friend.command;
import java.util.List;
import mineplex.core.command.CommandBase;
import mineplex.core.common.Rank;
import mineplex.core.friend.FriendManager;
import mineplex.core.friend.ui.FriendsGUI;
import mineplex.core.preferences.Preference;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
public class AddFriend extends CommandBase<FriendManager>
@ -39,4 +43,10 @@ public class AddFriend extends CommandBase<FriendManager>
});
}
}
@Override
public List<String> onTabComplete(CommandSender sender, String commandLabel, String[] args)
{
return tabCompletePlayerNames(sender, commandLabel, args);
}
}

View File

@ -1,5 +1,8 @@
package mineplex.core.message.commands;
import java.util.List;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import mineplex.core.command.CommandBase;
@ -28,4 +31,10 @@ public class MessageAdminCommand extends CommandBase<MessageManager>
Plugin.sendMessage(caller, args[0], message, false, true);
}
}
@Override
public List<String> onTabComplete(CommandSender sender, String commandLabel, String[] args)
{
return tabCompletePlayerNames(sender, commandLabel, args);
}
}

View File

@ -1,5 +1,8 @@
package mineplex.core.message.commands;
import java.util.List;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import mineplex.core.command.CommandBase;
@ -10,38 +13,38 @@ import mineplex.core.message.MessageManager;
public class MessageCommand extends CommandBase<MessageManager>
{
public MessageCommand(MessageManager plugin)
{
super(plugin, Rank.ALL, "m", "msg", "message", "tell", "t", "w", "whisper", "MSG");
}
public MessageCommand(MessageManager plugin)
{
super(plugin, Rank.ALL, "m", "msg", "message", "tell", "t", "w", "whisper", "MSG");
}
@Override
public void Execute(Player caller, String[] args)
{
if (args == null || args.length == 0)
{
Plugin.Help(caller);
}
else
{
if (args.length == 0)
{
UtilPlayer.message(caller, F.main(Plugin.getName(), "Player argument missing."));
return;
}
@Override
public void Execute(Player caller, String[] args)
{
if (args == null || args.length == 0)
{
UtilPlayer.message(caller, F.main(Plugin.getName(), "You didn't specify someone to message!"));
}
else
{
// Parse Message
String message;
if (args.length > 1)
{
message = F.combine(args, 1, null, false);
}
else
{
message = Plugin.GetRandomMessage();
}
// Parse Message
String message = "Beep!";
if (args.length > 1)
{
message = F.combine(args, 1, null, false);
}
else
{
message = Plugin.GetRandomMessage();
}
Plugin.sendMessage(caller, args[0], message, false, false);
}
}
Plugin.sendMessage(caller, args[0], message, false, false);
}
}
@Override
public List<String> onTabComplete(CommandSender sender, String commandLabel, String[] args)
{
return tabCompletePlayerNames(sender, commandLabel, args);
}
}

View File

@ -54,7 +54,7 @@ public class PartyCommand extends MultiCommandBase<PartyManager>
}
@Override
public List<String> onTabComplete(CommandSender sender, String commandLabel, String[] args, boolean endsWithSpace)
public List<String> onTabComplete(CommandSender sender, String commandLabel, String[] args)
{
if (sender instanceof Player)
{
@ -75,7 +75,7 @@ public class PartyCommand extends MultiCommandBase<PartyManager>
args = newArgs;
}
}
return super.onTabComplete(sender, commandLabel, args, endsWithSpace);
return super.onTabComplete(sender, commandLabel, args);
}
}

View File

@ -1,19 +1,15 @@
package mineplex.core.party.command.cli;
import java.util.List;
import java.util.stream.Collectors;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import mineplex.core.PlayerSelector;
import mineplex.core.command.CommandBase;
import mineplex.core.common.Rank;
import mineplex.core.common.util.F;
import mineplex.core.common.util.UtilLambda;
import mineplex.core.common.util.UtilPlayer;
import mineplex.core.party.InviteData;
import mineplex.core.party.Party;
import mineplex.core.party.PartyManager;
public class PartyAcceptCommand extends CommandBase<PartyManager>
@ -36,22 +32,15 @@ public class PartyAcceptCommand extends CommandBase<PartyManager>
}
@Override
public List<String> onTabComplete(CommandSender sender, String commandLabel, String[] args, boolean endsWithSpace)
public List<String> onTabComplete(CommandSender sender, String commandLabel, String[] args)
{
if (sender instanceof Player)
{
Player player = (Player) sender;
if (args.length == 1)
{
if (!endsWithSpace)
{
return getMatches(args[0], Plugin.getInviteManager().getAllInvites(player).stream().map(InviteData::getInviterName).collect(Collectors.toList()));
}
}
else if (args.length == 0)
{
return Plugin.getInviteManager().getAllInvites(player).stream().map(InviteData::getInviterName).collect(Collectors.toList());
Player player = (Player) sender;
return getMatches(args[0], Plugin.getInviteManager().getAllInvites(player).stream().map(InviteData::getInviterName));
}
}

View File

@ -32,22 +32,14 @@ public class PartyDenyCommand extends CommandBase<PartyManager>
}
@Override
public List<String> onTabComplete(CommandSender sender, String commandLabel, String[] args, boolean endsWithSpace)
public List<String> onTabComplete(CommandSender sender, String commandLabel, String[] args)
{
if (sender instanceof Player)
{
Player player = (Player) sender;
if (args.length == 1)
{
if (!endsWithSpace)
{
return getMatches(args[0], Plugin.getInviteManager().getAllInvites(player).stream().map(InviteData::getInviterName).collect(Collectors.toList()));
}
}
else if (args.length == 0)
{
return Plugin.getInviteManager().getAllInvites(player).stream().map(InviteData::getInviterName).collect(Collectors.toList());
Player player = (Player) sender;
return getMatches(args[0], Plugin.getInviteManager().getAllInvites(player).stream().map(InviteData::getInviterName).collect(Collectors.toList()));
}
}

View File

@ -32,14 +32,14 @@ public class PartyInviteCommand extends CommandBase<PartyManager>
}
@Override
public List<String> onTabComplete(CommandSender sender, String commandLabel, String[] args, boolean endsWithSpace)
public List<String> onTabComplete(CommandSender sender, String commandLabel, String[] args)
{
if (sender instanceof Player)
{
Player player = (Player) sender;
Party party = Plugin.getPartyByPlayer(player);
return tabCompletePlayerNames(sender, commandLabel, args, endsWithSpace, other -> party == null || !party.isMember(other));
return tabCompletePlayerNames(sender, commandLabel, args, other -> party == null || !party.isMember(other));
}
return null;

View File

@ -41,7 +41,7 @@ public class PartyKickCommand extends CommandBase<PartyManager>
}
@Override
public List<String> onTabComplete(CommandSender sender, String commandLabel, String[] args, boolean endsWithSpace)
public List<String> onTabComplete(CommandSender sender, String commandLabel, String[] args)
{
if (sender instanceof Player)
{
@ -50,7 +50,7 @@ public class PartyKickCommand extends CommandBase<PartyManager>
if (party != null && party.isOwner(player))
{
return tabCompletePlayerNames(sender, commandLabel, args, endsWithSpace, other -> other != player && party.isMember(other));
return tabCompletePlayerNames(sender, commandLabel, args, other -> other != player && party.isMember(other));
}
}

View File

@ -68,7 +68,7 @@ public class PartyTransferOwnerCommand extends CommandBase<PartyManager>
}
@Override
public List<String> onTabComplete(CommandSender sender, String commandLabel, String[] args, boolean endsWithSpace)
public List<String> onTabComplete(CommandSender sender, String commandLabel, String[] args)
{
if (sender instanceof Player)
{
@ -77,7 +77,7 @@ public class PartyTransferOwnerCommand extends CommandBase<PartyManager>
if (party != null && party.isOwner(player))
{
return tabCompletePlayerNames(sender, commandLabel, args, endsWithSpace, other -> other != player && party.isMember(other));
return tabCompletePlayerNames(sender, commandLabel, args, other -> other != player && party.isMember(other));
}
}

View File

@ -31,8 +31,16 @@ public class PartyGUIInviteCommand extends CommandBase<PartyManager>
}
@Override
public List<String> onTabComplete(CommandSender sender, String commandLabel, String[] args, boolean endsWithSpace)
public List<String> onTabComplete(CommandSender sender, String commandLabel, String[] args)
{
return tabCompletePlayerNames(sender, commandLabel, args, endsWithSpace);
if (sender instanceof Player)
{
Player player = (Player) sender;
Party party = Plugin.getPartyByPlayer(player);
return tabCompletePlayerNames(sender, commandLabel, args, other -> party == null || !party.isMember(other));
}
return null;
}
}

View File

@ -141,8 +141,8 @@ public class PunishCommand extends CommandBase<Punish>
}
@Override
public List<String> onTabComplete(CommandSender sender, String commandLabel, String[] args, boolean endsWithSpace)
public List<String> onTabComplete(CommandSender sender, String commandLabel, String[] args)
{
return tabCompletePlayerNames(sender, commandLabel, args, endsWithSpace);
return tabCompletePlayerNames(sender, commandLabel, args);
}
}

View File

@ -344,103 +344,92 @@ public class SetCommand extends CommandBase<ArcadeManager>
}
@Override
public List<String> onTabComplete(CommandSender sender, String commandLabel, String[] args,
boolean endsWithSpace)
public List<String> onTabComplete(CommandSender sender, String commandLabel, String[] args)
{
if (!(sender instanceof Player) || !Plugin.canPlayerUseGameCmd((Player) sender))
{
return null;
}
if (args.length == 0)
if (args.length == 1)
{
return matchGameType("", true).stream().map(Enum::name).collect(Collectors.toList());
}
else if (args.length == 1)
{
if (!endsWithSpace)
{
return matchGameType(args[0], true).stream().map(Enum::name).collect(Collectors.toList());
}
return matchGameType(args[0], true).stream().map(Enum::name).collect(Collectors.toList());
}
else
{
if (!endsWithSpace)
if (isValid(args))
{
if (isValid(args))
List<GameType> matches = matchGameType(args[0], true);
if (matches.size() == 1)
{
List<GameType> matches = matchGameType(args[0], true);
GameType gameType = matches.get(0);
if (matches.size() == 1)
String gameModeStr = findGameMode(args);
String gameSourceStr = findGameSource(args);
String mapStr = findMap(args);
String lastArg = args[args.length - 1];
if (lastArg.startsWith(MODE_PREFIX))
{
GameType gameType = matches.get(0);
String gameModeStr = findGameMode(args);
String gameSourceStr = findGameSource(args);
String mapStr = findMap(args);
String lastArg = args[args.length - 1];
if (lastArg.startsWith(MODE_PREFIX))
if (gameType.hasGamemodes())
{
if (gameType.hasGamemodes())
{
return matchGameMode(gameType, gameModeStr, true).stream().map(mode -> MODE_PREFIX + mode.getName().replaceAll(" ", "")).collect(Collectors.toList());
}
return matchGameMode(gameType, gameModeStr, true).stream().map(mode -> MODE_PREFIX + mode.getName().replaceAll(" ", "")).collect(Collectors.toList());
}
else if (lastArg.startsWith(SOURCE_PREFIX))
}
else if (lastArg.startsWith(SOURCE_PREFIX))
{
Class<? extends Game> gameClass = gameType.getGameClass();
if (gameType.hasGamemodes())
{
Class<? extends Game> gameClass = gameType.getGameClass();
if (gameType.hasGamemodes())
{
// If there are gamemodes, you must provide a gamemode type
if (gameModeStr == null)
return null;
List<GameMode> matchedModes = matchGameMode(gameType, gameModeStr, true);
// If more than one mode has been matched, we can't show sources
if (matchedModes.size() != 1)
return null;
gameClass = matchedModes.get(0).getGameClass();
}
return getSources(gameType, gameClass, gameSourceStr, true).stream().map(type -> SOURCE_PREFIX + type.name().replaceAll(" ", "")).collect(Collectors.toList());
}
else if (lastArg.startsWith(MAP_PREFIX))
{
Class<? extends Game> gameClass = gameType.getGameClass();
if (gameType.hasGamemodes())
{
// If the game has a gamemode, the mode type must be set
if (gameModeStr == null)
return null;
List<GameMode> matchedModes = matchGameMode(gameType, gameModeStr, true);
// If more than one mode has been matched, we can't show maps
if (matchedModes.size() != 1)
return null;
gameClass = matchedModes.get(0).getGameClass();
}
// No particular source specified, we'll use all of them
if (gameSourceStr == null)
{
List<GameType> mapTypes = Arrays.asList(Game.GetWorldHostNames(gameType, gameClass));
return matchMaps(mapTypes, mapStr, true).stream().map(str -> MAP_PREFIX + str).collect(Collectors.toList());
}
List<GameType> sources = getSources(gameType, gameClass, gameSourceStr, true);
// If a source has been provided, it must be valid
if (sources.size() != 1)
// If there are gamemodes, you must provide a gamemode type
if (gameModeStr == null)
return null;
return matchMaps(sources, mapStr, true).stream().map(str -> MAP_PREFIX + str).collect(Collectors.toList());
List<GameMode> matchedModes = matchGameMode(gameType, gameModeStr, true);
// If more than one mode has been matched, we can't show sources
if (matchedModes.size() != 1)
return null;
gameClass = matchedModes.get(0).getGameClass();
}
return getSources(gameType, gameClass, gameSourceStr, true).stream().map(type -> SOURCE_PREFIX + type.name().replaceAll(" ", "")).collect(Collectors.toList());
}
else if (lastArg.startsWith(MAP_PREFIX))
{
Class<? extends Game> gameClass = gameType.getGameClass();
if (gameType.hasGamemodes())
{
// If the game has a gamemode, the mode type must be set
if (gameModeStr == null)
return null;
List<GameMode> matchedModes = matchGameMode(gameType, gameModeStr, true);
// If more than one mode has been matched, we can't show maps
if (matchedModes.size() != 1)
return null;
gameClass = matchedModes.get(0).getGameClass();
}
// No particular source specified, we'll use all of them
if (gameSourceStr == null)
{
List<GameType> mapTypes = Arrays.asList(Game.GetWorldHostNames(gameType, gameClass));
return matchMaps(mapTypes, mapStr, true).stream().map(str -> MAP_PREFIX + str).collect(Collectors.toList());
}
List<GameType> sources = getSources(gameType, gameClass, gameSourceStr, true);
// If a source has been provided, it must be valid
if (sources.size() != 1)
return null;
return matchMaps(sources, mapStr, true).stream().map(str -> MAP_PREFIX + str).collect(Collectors.toList());
}
}
}