From e0ae1928e90566b0f39eb4ff3b3b3fa32fde7a02 Mon Sep 17 00:00:00 2001 From: Ryan Barlow <7389646+ryanbarlow97@users.noreply.github.com> Date: Thu, 15 Oct 2026 18:10:53 +0000 Subject: [PATCH] fix: complete configured resource labels and filter command prefixes --- .../dowsing/utils/TabCompletion.java | 97 +++++++------------ .../managers/CommandAndResourceTest.java | 52 ++++++++-- 2 files changed, 83 insertions(+), 66 deletions(-) diff --git a/src/main/java/net/tfminecraft/dowsing/utils/TabCompletion.java b/src/main/java/net/tfminecraft/dowsing/utils/TabCompletion.java index c3ebb8b..61c5202 100644 --- a/src/main/java/net/tfminecraft/dowsing/utils/TabCompletion.java +++ b/src/main/java/net/tfminecraft/dowsing/utils/TabCompletion.java @@ -3,72 +3,49 @@ import java.io.File; import java.util.ArrayList; import java.util.List; - +import java.util.Locale; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.bukkit.command.TabCompleter; import org.bukkit.entity.Player; -public class TabCompletion implements TabCompleter{ +import net.tfminecraft.dowsing.DowsingMain; +import net.tfminecraft.dowsing.loaders.TypeLoader; +import net.tfminecraft.dowsing.objects.NodeType; + +public class TabCompletion implements TabCompleter { @Override - public List onTabComplete (CommandSender sender, Command cmd, String label, String[] args){ - if(Permissions.isAdmin(sender)) { - if(cmd.getName().equalsIgnoreCase("dowsing") && args.length < 2 && (args.length == 0 || !(args[0].equalsIgnoreCase("reload") || args[0].equalsIgnoreCase("createresource") || args[0].equalsIgnoreCase("deleteresource")))){ - if(sender instanceof Player){ - List completions = new ArrayList<>(); - - completions.add("createresource"); - completions.add("deleteresource"); - completions.add("reload"); - return completions; - } - } else if(cmd.getName().equalsIgnoreCase("dowsing") && args.length == 2 && args[0].equalsIgnoreCase("createresource")){ - if(sender instanceof Player){ - List completions = new ArrayList(); - completions.add(""); - - return completions; - } - } else if(cmd.getName().equalsIgnoreCase("dowsing") && args.length == 3 && args[0].equalsIgnoreCase("createresource")){ - if(sender instanceof Player){ - List completions = new ArrayList(); - completions.add(""); - - return completions; - } - } else if(cmd.getName().equalsIgnoreCase("dowsing") && args.length == 4 && args[0].equalsIgnoreCase("createresource")){ - if(sender instanceof Player){ - List completions = new ArrayList(); - completions.add("1"); - completions.add("2"); - completions.add("3"); - completions.add("4"); - completions.add("5"); - completions.add("6"); - completions.add("7"); - completions.add("8"); - - return completions; - } - }else if(cmd.getName().equalsIgnoreCase("dowsing") && args.length == 2 && args[0].equalsIgnoreCase("deleteresource")){ - if(sender instanceof Player){ - List completions = new ArrayList(); - File folder = new File(net.tfminecraft.dowsing.DowsingMain.plugin.getDataFolder(), "Resources"); - File[] files = folder.listFiles(); - if (files == null) return completions; - for (final File file : files) { - if (!file.isDirectory()) { - String id = new String(file.getName()); - id = id.replace(".txt", ""); - completions.add(id); - } - } - - return completions; - } - } - } - return null; + public List onTabComplete(CommandSender sender, Command cmd, String label, String[] args) { + if (!Permissions.isAdmin(sender) || !cmd.getName().equalsIgnoreCase("dowsing")) return List.of(); + String prefix = args.length == 0 ? "" : args[args.length - 1]; + if (args.length < 2) { + return matching(sender instanceof Player + ? List.of("createresource", "deleteresource", "reload") : List.of("reload"), prefix); + } + if (!(sender instanceof Player)) return List.of(); + if (args[0].equalsIgnoreCase("createresource")) { + if (args.length == 3) { + return matching(TypeLoader.getNodeTypes().stream().map(NodeType::getResource) + .filter(resource -> resource != null && !resource.isBlank()).distinct().toList(), prefix); + } + if (args.length == 4) return matching(List.of("1", "2", "3", "4", "5", "6", "7", "8"), prefix); + } else if (args.length == 2 && args[0].equalsIgnoreCase("deleteresource")) { + List ids = new ArrayList<>(); + File[] files = new File(DowsingMain.plugin.getDataFolder(), "Resources").listFiles(); + if (files != null) { + for (File file : files) { + String name = file.getName(); + if (file.isFile() && name.endsWith(".txt")) ids.add(name.substring(0, name.length() - 4)); + } + } + return matching(ids, prefix); + } + return List.of(); + } + + private static List matching(List values, String prefix) { + String lower = prefix.toLowerCase(Locale.ROOT); + return values.stream().filter(value -> value.toLowerCase(Locale.ROOT).startsWith(lower)).toList(); } } diff --git a/src/test/java/net/tfminecraft/dowsing/managers/CommandAndResourceTest.java b/src/test/java/net/tfminecraft/dowsing/managers/CommandAndResourceTest.java index 73cd35e..fd20f73 100644 --- a/src/test/java/net/tfminecraft/dowsing/managers/CommandAndResourceTest.java +++ b/src/test/java/net/tfminecraft/dowsing/managers/CommandAndResourceTest.java @@ -66,14 +66,54 @@ class CommandAndResourceTest { assertEquals(List.of(),tabs.onTabComplete(player,command,"dowsing",new String[]{"deleteresource",""})); Files.createDirectories(root.resolve("Resources/nested")); Files.writeString(root.resolve("Resources/iron.txt"),""); assertEquals(List.of("iron"),tabs.onTabComplete(player,command,"dowsing",new String[]{"deleteresource",""})); - assertEquals(List.of(""),tabs.onTabComplete(player,command,"",new String[]{"createresource",""})); - assertEquals(List.of(""),tabs.onTabComplete(player,command,"",new String[]{"createresource","x",""})); + assertEquals(List.of(),tabs.onTabComplete(player,command,"",new String[]{"createresource",""})); assertEquals(List.of("1","2","3","4","5","6","7","8"),tabs.onTabComplete(player,command,"",new String[]{"createresource","x","y",""})); - assertNull(tabs.onTabComplete(player,command,"",new String[]{"reload"})); + assertEquals(List.of("reload"),tabs.onTabComplete(player,command,"",new String[]{"reload"})); CommandSender console=mock(CommandSender.class); when(console.hasPermission(Permissions.Permission_Admin)).thenReturn(true); - for(String[] args:List.of(new String[]{""},new String[]{"createresource",""},new String[]{"createresource","x",""},new String[]{"createresource","x","y",""},new String[]{"deleteresource",""})) assertNull(tabs.onTabComplete(console,command,"",args)); - when(command.getName()).thenReturn("other"); assertNull(tabs.onTabComplete(player,command,"",new String[]{""})); - when(player.hasPermission(Permissions.Permission_Admin)).thenReturn(false); assertNull(tabs.onTabComplete(player,command,"",new String[]{""})); + assertEquals(List.of("reload"),tabs.onTabComplete(console,command,"",new String[]{""})); + for(String[] args:List.of(new String[]{"createresource",""},new String[]{"createresource","x",""},new String[]{"createresource","x","y",""},new String[]{"deleteresource",""})) assertEquals(List.of(),tabs.onTabComplete(console,command,"",args)); + when(command.getName()).thenReturn("other"); assertEquals(List.of(),tabs.onTabComplete(player,command,"",new String[]{""})); + when(player.hasPermission(Permissions.Permission_Admin)).thenReturn(false); assertEquals(List.of(),tabs.onTabComplete(player,command,"",new String[]{""})); + } + @Test void completionFiltersEveryCurrentTokenAndUsesLoadedResourceLabels() throws Exception { + TabCompletion tabs = new TabCompletion(); + Files.createDirectories(root.resolve("Resources")); + Files.writeString(root.resolve("Resources/iron.txt"), ""); + Files.writeString(root.resolve("Resources/ignored.json"), ""); + var mineral = mock(net.tfminecraft.dowsing.objects.NodeType.class); + var duplicate = mock(net.tfminecraft.dowsing.objects.NodeType.class); + var magic = mock(net.tfminecraft.dowsing.objects.NodeType.class); + var missing = mock(net.tfminecraft.dowsing.objects.NodeType.class); + var blank = mock(net.tfminecraft.dowsing.objects.NodeType.class); + when(mineral.getResource()).thenReturn("mineral"); + when(duplicate.getResource()).thenReturn("mineral"); + when(magic.getResource()).thenReturn("Magic"); + when(blank.getResource()).thenReturn(" "); + try (var types = mockStatic(net.tfminecraft.dowsing.loaders.TypeLoader.class)) { + types.when(net.tfminecraft.dowsing.loaders.TypeLoader::getNodeTypes) + .thenReturn(List.of(mineral, duplicate, magic, missing, blank)); + assertEquals(List.of("reload"), tabs.onTabComplete(player, command, "", new String[]{"RE"})); + assertEquals(List.of("reload"), tabs.onTabComplete(player, command, "", new String[]{"reload"})); + assertEquals(List.of("iron"), tabs.onTabComplete(player, command, "", new String[]{"DELETERESOURCE", "IR"})); + assertEquals(List.of("mineral", "Magic"), tabs.onTabComplete(player, command, "", new String[]{"createresource", "id", ""})); + assertEquals(List.of("mineral"), tabs.onTabComplete(player, command, "", new String[]{"CREATERESOURCE", "id", "mI"})); + assertEquals(List.of("2"), tabs.onTabComplete(player, command, "", new String[]{"createresource", "id", "mineral", "2"})); + for (String[] args : List.of(new String[]{"absent"}, new String[]{"reload", ""}, + new String[]{"deleteresource", "missing"}, new String[]{"createresource", "id", "missing"}, + new String[]{"createresource", "id", "mineral", "9"}, new String[]{"createresource", "id", "mineral", "2", ""})) { + assertTrue(tabs.onTabComplete(player, command, "", args).isEmpty()); + } + types.when(net.tfminecraft.dowsing.loaders.TypeLoader::getNodeTypes).thenReturn(List.of(magic)); + assertTrue(tabs.onTabComplete(player, command, "", new String[]{"createresource", "id", "mi"}).isEmpty()); + assertEquals(List.of("Magic"), tabs.onTabComplete(player, command, "", new String[]{"createresource", "id", ""})); + CommandSender console = mock(CommandSender.class); + when(console.hasPermission(Permissions.Permission_Admin)).thenReturn(true); + assertEquals(List.of("reload"), tabs.onTabComplete(console, command, "", new String[]{"rE"})); + assertTrue(tabs.onTabComplete(console, command, "", new String[]{"create"}).isEmpty()); + assertTrue(tabs.onTabComplete(console, command, "", new String[]{"reload", ""}).isEmpty()); + when(console.hasPermission(Permissions.Permission_Admin)).thenReturn(false); + assertTrue(tabs.onTabComplete(console, command, "", new String[]{""}).isEmpty()); + } } @Test void dowsingStickHandlesActionsCooldownTypeAndYieldColors() throws Exception { String previousStick=Cache.dowsingStick; Boolean previousEnabled=Cache.naturalYieldEnabled;