diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/chatnotifications/ChatNotificationsConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/chatnotifications/ChatNotificationsConfig.java index 8c254a2c2a..9b9cd45479 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/chatnotifications/ChatNotificationsConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/chatnotifications/ChatNotificationsConfig.java @@ -28,12 +28,44 @@ package net.runelite.client.plugins.chatnotifications; import net.runelite.client.config.Config; import net.runelite.client.config.ConfigGroup; import net.runelite.client.config.ConfigItem; +import net.runelite.client.config.ConfigSection; @ConfigGroup("chatnotification") public interface ChatNotificationsConfig extends Config { + @ConfigSection( + name = "Highlight Lists", + description = "Custom single word and regex filter lists", + position = 0 + ) + String highlightLists = "highlightLists"; + @ConfigItem( - position = 0, + position = 1, + keyName = "highlightWordsString", + name = "Highlight words", + description = "Highlights the following words in chat", + section = highlightLists + ) + default String highlightWordsString() + { + return ""; + } + + @ConfigItem( + position = 2, + keyName = "highlightRegexString", + name = "Highlight Regex", + description = "Highlights the following regular expressions in chat, one per line", + section = highlightLists + ) + default String highlightRegexString() + { + return ""; + } + + @ConfigItem( + position = 1, keyName = "highlightOwnName", name = "Highlight own name", description = "Highlights any instance of your username in chat" @@ -43,17 +75,6 @@ public interface ChatNotificationsConfig extends Config return true; } - @ConfigItem( - position = 1, - keyName = "highlightWordsString", - name = "Highlight words", - description = "Highlights the following words in chat" - ) - default String highlightWordsString() - { - return ""; - } - @ConfigItem( position = 2, keyName = "notifyOnOwnName", diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/chatnotifications/ChatNotificationsPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/chatnotifications/ChatNotificationsPlugin.java index a869f7136b..9c29b4798c 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/chatnotifications/ChatNotificationsPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/chatnotifications/ChatNotificationsPlugin.java @@ -27,12 +27,16 @@ package net.runelite.client.plugins.chatnotifications; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.MoreObjects; +import com.google.common.base.Splitter; import com.google.common.base.Strings; import com.google.inject.Provides; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Objects; import java.util.regex.Matcher; import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; import java.util.stream.Collectors; import javax.inject.Inject; import javax.inject.Named; @@ -77,7 +81,7 @@ public class ChatNotificationsPlugin extends Plugin //Custom Highlights private Pattern usernameMatcher = null; - private Pattern highlightMatcher = null; + private final List highlightPatterns = new ArrayList<>(); @Provides ChatNotificationsConfig provideConfig(ConfigManager configManager) @@ -91,6 +95,13 @@ public class ChatNotificationsPlugin extends Plugin updateHighlights(); } + @Override + protected void shutDown() + { + usernameMatcher = null; + highlightPatterns.clear(); + } + @Subscribe public void onGameStateChanged(GameStateChanged event) { @@ -114,7 +125,7 @@ public class ChatNotificationsPlugin extends Plugin private void updateHighlights() { - highlightMatcher = null; + highlightPatterns.clear(); if (!config.highlightWordsString().trim().equals("")) { @@ -125,7 +136,28 @@ public class ChatNotificationsPlugin extends Plugin .collect(Collectors.joining("|")); // To match \b doesn't work due to <> not being in \w, // so match \b or \s, as well as \A and \z for beginning and end of input respectively - highlightMatcher = Pattern.compile("(?:\\b|(?<=\\s)|\\A)(?:" + joined + ")(?:\\b|(?=\\s)|\\z)", Pattern.CASE_INSENSITIVE); + highlightPatterns.add(Pattern.compile("(?:\\b|(?<=\\s)|\\A)(?:" + joined + ")(?:\\b|(?=\\s)|\\z)", Pattern.CASE_INSENSITIVE)); + } + + Splitter + .on("\n") + .omitEmptyStrings() + .trimResults() + .splitToList(config.highlightRegexString()).stream() + .map(ChatNotificationsPlugin::compilePattern) + .filter(Objects::nonNull) + .forEach(highlightPatterns::add); + } + + private static Pattern compilePattern(String pattern) + { + try + { + return Pattern.compile(pattern, Pattern.CASE_INSENSITIVE); + } + catch (PatternSyntaxException ex) + { + return null; } } @@ -225,14 +257,22 @@ public class ChatNotificationsPlugin extends Plugin } } - if (highlightMatcher != null) + boolean matchesHighlight = false; + // Get nodeValue to store and update in between the different pattern passes + // The messageNode value is only set after all patterns have been processed + String nodeValue = messageNode.getValue(); + + for (Pattern pattern : highlightPatterns) { - String nodeValue = messageNode.getValue(); - Matcher matcher = highlightMatcher.matcher(nodeValue); - boolean found = false; + Matcher matcher = pattern.matcher(nodeValue); + if (!matcher.find()) + { + continue; + } + StringBuffer stringBuffer = new StringBuffer(); - while (matcher.find()) + do { String value = matcher.group(); @@ -256,18 +296,21 @@ public class ChatNotificationsPlugin extends Plugin stringBuffer.append(endColor == null ? "" : endColor); update = true; - found = true; + matchesHighlight = true; } + while (matcher.find()); - if (found) + // Append stringBuffer with remainder of message and update nodeValue + matcher.appendTail(stringBuffer); + nodeValue = stringBuffer.toString(); + } + + if (matchesHighlight) + { + messageNode.setValue(nodeValue); + if (config.notifyOnHighlight()) { - matcher.appendTail(stringBuffer); - messageNode.setValue(stringBuffer.toString()); - - if (config.notifyOnHighlight()) - { - sendNotification(chatMessage); - } + sendNotification(chatMessage); } } @@ -288,7 +331,7 @@ public class ChatNotificationsPlugin extends Plugin { stringBuilder.append('[').append(sender).append("] "); } - + if (!Strings.isNullOrEmpty(name)) { stringBuilder.append(name).append(": "); diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/chatnotifications/ChatNotificationsPluginTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/chatnotifications/ChatNotificationsPluginTest.java index e87e72628d..0ca58fa457 100644 --- a/runelite-client/src/test/java/net/runelite/client/plugins/chatnotifications/ChatNotificationsPluginTest.java +++ b/runelite-client/src/test/java/net/runelite/client/plugins/chatnotifications/ChatNotificationsPluginTest.java @@ -82,6 +82,8 @@ public class ChatNotificationsPluginTest public void before() { Guice.createInjector(BoundFieldModule.of(this)).injectMembers(this); + when(config.highlightRegexString()).thenReturn(""); + when(config.highlightWordsString()).thenReturn(""); } @Test @@ -102,6 +104,42 @@ public class ChatNotificationsPluginTest verify(messageNode).setValue("Deathbeam, Deathbeam OSRS"); } + @Test + public void testRegexMultiplePatternsMessage() + { + when(config.highlightRegexString()).thenReturn("brandie+\ntest"); + + MessageNode messageNode = mock(MessageNode.class); + when(messageNode.getValue()).thenReturn("brandieeee testing"); + + ChatMessage chatMessage = new ChatMessage(); + chatMessage.setType(ChatMessageType.PUBLICCHAT); + chatMessage.setMessageNode(messageNode); + + chatNotificationsPlugin.startUp(); + chatNotificationsPlugin.onChatMessage(chatMessage); + + verify(messageNode).setValue("brandieeee testing"); + } + + @Test + public void testRegexMultiplePatternsWithOnlyOneMatch() + { + when(config.highlightRegexString()).thenReturn("brandie+\nwillNotMatch"); + + MessageNode messageNode = mock(MessageNode.class); + when(messageNode.getValue()).thenReturn("brandieeee testing"); + + ChatMessage chatMessage = new ChatMessage(); + chatMessage.setType(ChatMessageType.PUBLICCHAT); + chatMessage.setMessageNode(messageNode); + + chatNotificationsPlugin.startUp(); + chatNotificationsPlugin.onChatMessage(chatMessage); + + verify(messageNode).setValue("brandieeee testing"); + } + @Test public void testLtGt() { @@ -179,7 +217,7 @@ public class ChatNotificationsPluginTest } @Test - public void testPreceedingColor() + public void testPrecedingColor() { when(config.highlightWordsString()).thenReturn("you. It"); @@ -239,10 +277,10 @@ public class ChatNotificationsPluginTest public void highlightListTest() { when(config.highlightWordsString()).thenReturn("this,is, a , test, "); - final List higlights = Text.fromCSV(config.highlightWordsString()); - assertEquals(4, higlights.size()); + final List highlights = Text.fromCSV(config.highlightWordsString()); + assertEquals(4, highlights.size()); - final Iterator iterator = higlights.iterator(); + final Iterator iterator = highlights.iterator(); assertEquals("this", iterator.next()); assertEquals("is", iterator.next()); assertEquals("a", iterator.next());