From aa56f385f85c8fccaffadf974c9958d62455d4dd Mon Sep 17 00:00:00 2001 From: Marcos Paulo Date: Thu, 20 Aug 2026 16:12:50 -0300 Subject: [PATCH] fix(titles): improve title matching with accent normalization and removal aliases --- .../canalhandia/CanalhandiaCommand.java | 29 +++++++++++++++---- .../marcospaulo/canalhandia/TitlesTest.java | 6 +++- 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/src/main/java/dev/marcospaulo/canalhandia/CanalhandiaCommand.java b/src/main/java/dev/marcospaulo/canalhandia/CanalhandiaCommand.java index 209b11a..6c80348 100644 --- a/src/main/java/dev/marcospaulo/canalhandia/CanalhandiaCommand.java +++ b/src/main/java/dev/marcospaulo/canalhandia/CanalhandiaCommand.java @@ -1530,8 +1530,10 @@ final class CanalhandiaCommand implements CommandExecutor, TabCompleter { } return true; } - String arg = String.join(" ", args); - if (arg.equalsIgnoreCase("limpar") || arg.equalsIgnoreCase("nenhum")) { + String arg = String.join(" ", args).trim(); + if (arg.equalsIgnoreCase("limpar") || arg.equalsIgnoreCase("nenhum") + || arg.equalsIgnoreCase("remover") || arg.equalsIgnoreCase("remove") + || arg.equalsIgnoreCase("clear")) { plugin.titles().clear(player.getUniqueId()); Msg.ok(player, Lang.tr("canalhandia.cmd.titulo.removido")); return true; @@ -1546,20 +1548,37 @@ final class CanalhandiaCommand implements CommandExecutor, TabCompleter { return true; } - /** Matches typed text to an earned achievement by key or (case-insensitive) title. */ + /** Matches typed text to an earned achievement by key, title, or accent-normalized text. */ static Achievement matchEarned(String text, List earned) { - Achievement byKey = Achievement.byKey(text); + if (text == null || text.isBlank() || earned == null || earned.isEmpty()) { + return null; + } + String clean = text.trim(); + Achievement byKey = Achievement.byKey(clean); if (byKey != null && earned.contains(byKey)) { return byKey; } for (Achievement achievement : earned) { - if (achievement.title().equalsIgnoreCase(text.trim())) { + if (achievement.title().equalsIgnoreCase(clean)) { + return achievement; + } + } + String normalizedClean = normalizeText(clean); + for (Achievement achievement : earned) { + if (normalizeText(achievement.title()).equalsIgnoreCase(normalizedClean) + || normalizeText(achievement.key()).equalsIgnoreCase(normalizedClean)) { return achievement; } } return null; } + private static String normalizeText(String input) { + if (input == null) return ""; + return java.text.Normalizer.normalize(input, java.text.Normalizer.Form.NFD) + .replaceAll("\\p{M}", ""); + } + private static String titlesList(List earned) { List names = new ArrayList<>(); for (Achievement achievement : earned) { diff --git a/src/test/java/dev/marcospaulo/canalhandia/TitlesTest.java b/src/test/java/dev/marcospaulo/canalhandia/TitlesTest.java index 89a39c9..ba7a1b7 100644 --- a/src/test/java/dev/marcospaulo/canalhandia/TitlesTest.java +++ b/src/test/java/dev/marcospaulo/canalhandia/TitlesTest.java @@ -25,10 +25,14 @@ class TitlesTest { void matchesEarnedTitleByKeyAndByName() { Achievement pedreiro = Achievement.byKey("pedreiro"); Achievement veterano = Achievement.byKey("veterano"); - List earned = List.of(pedreiro, veterano); + Achievement cacador = Achievement.byKey("cacador"); + List earned = List.of(pedreiro, veterano, cacador); assertSame(pedreiro, CanalhandiaCommand.matchEarned("pedreiro", earned)); assertSame(veterano, CanalhandiaCommand.matchEarned("Veterano", earned)); // display name, ci assertSame(pedreiro, CanalhandiaCommand.matchEarned("Pedreiro", earned)); + assertSame(cacador, CanalhandiaCommand.matchEarned("cacador", earned)); + assertSame(cacador, CanalhandiaCommand.matchEarned("Caçador", earned)); + assertSame(cacador, CanalhandiaCommand.matchEarned("Cacador", earned)); } @Test