chat notifications: fix matching messages with color
This commit is contained in:
@@ -25,6 +25,7 @@
|
|||||||
*/
|
*/
|
||||||
package net.runelite.client.plugins.chatnotifications;
|
package net.runelite.client.plugins.chatnotifications;
|
||||||
|
|
||||||
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
import com.google.common.base.Strings;
|
import com.google.common.base.Strings;
|
||||||
import com.google.inject.Provides;
|
import com.google.inject.Provides;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -115,7 +116,7 @@ public class ChatNotificationsPlugin extends Plugin
|
|||||||
List<String> items = Text.fromCSV(config.highlightWordsString());
|
List<String> items = Text.fromCSV(config.highlightWordsString());
|
||||||
String joined = items.stream()
|
String joined = items.stream()
|
||||||
.map(Text::escapeJagex) // we compare these strings to the raw Jagex ones
|
.map(Text::escapeJagex) // we compare these strings to the raw Jagex ones
|
||||||
.map(Pattern::quote)
|
.map(this::quoteAndIgnoreColor) // regex escape and ignore nested colors in the target message
|
||||||
.collect(Collectors.joining("|"));
|
.collect(Collectors.joining("|"));
|
||||||
// To match <word> \b doesn't work due to <> not being in \w,
|
// To match <word> \b doesn't work due to <> not being in \w,
|
||||||
// so match \b or \s
|
// so match \b or \s
|
||||||
@@ -184,7 +185,26 @@ public class ChatNotificationsPlugin extends Plugin
|
|||||||
while (matcher.find())
|
while (matcher.find())
|
||||||
{
|
{
|
||||||
String value = matcher.group();
|
String value = matcher.group();
|
||||||
matcher.appendReplacement(stringBuffer, "<col" + ChatColorType.HIGHLIGHT + ">" + value + "<col" + ChatColorType.NORMAL + ">");
|
|
||||||
|
// Determine the ending color by:
|
||||||
|
// 1) use the color from value if it has one
|
||||||
|
// 2) use the last color from stringBuffer + <content between last match and current match>
|
||||||
|
// To do #2 we just search for the last col tag after calling appendReplacement
|
||||||
|
String endColor = getLastColor(value);
|
||||||
|
|
||||||
|
// Strip color tags from the highlighted region so that it remains highlighted correctly
|
||||||
|
value = stripColor(value);
|
||||||
|
|
||||||
|
matcher.appendReplacement(stringBuffer, "<col" + ChatColorType.HIGHLIGHT + '>' + value);
|
||||||
|
|
||||||
|
if (endColor == null)
|
||||||
|
{
|
||||||
|
endColor = getLastColor(stringBuffer.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append end color
|
||||||
|
stringBuffer.append(endColor == null ? "<col" + ChatColorType.NORMAL + ">" : endColor);
|
||||||
|
|
||||||
update = true;
|
update = true;
|
||||||
found = true;
|
found = true;
|
||||||
}
|
}
|
||||||
@@ -228,4 +248,61 @@ public class ChatNotificationsPlugin extends Plugin
|
|||||||
String notification = stringBuilder.toString();
|
String notification = stringBuilder.toString();
|
||||||
notifier.notify(notification);
|
notifier.notify(notification);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String quoteAndIgnoreColor(String str)
|
||||||
|
{
|
||||||
|
StringBuilder stringBuilder = new StringBuilder();
|
||||||
|
|
||||||
|
for (int i = 0; i < str.length(); ++i)
|
||||||
|
{
|
||||||
|
char c = str.charAt(i);
|
||||||
|
stringBuilder.append(Pattern.quote(String.valueOf(c)));
|
||||||
|
stringBuilder.append("(?:<col=[^>]*?>)?");
|
||||||
|
}
|
||||||
|
|
||||||
|
return stringBuilder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the last color tag from a string, or null if there was none
|
||||||
|
*
|
||||||
|
* @param str
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private static String getLastColor(String str)
|
||||||
|
{
|
||||||
|
int colIdx = str.lastIndexOf("<col=");
|
||||||
|
int colEndIdx = str.lastIndexOf("</col>");
|
||||||
|
|
||||||
|
if (colEndIdx > colIdx)
|
||||||
|
{
|
||||||
|
// ends in a </col> which resets the color to normal
|
||||||
|
return "<col" + ChatColorType.NORMAL + ">";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (colIdx == -1)
|
||||||
|
{
|
||||||
|
return null; // no color
|
||||||
|
}
|
||||||
|
|
||||||
|
int closeIdx = str.indexOf('>', colIdx);
|
||||||
|
if (closeIdx == -1)
|
||||||
|
{
|
||||||
|
return null; // unclosed col tag
|
||||||
|
}
|
||||||
|
|
||||||
|
return str.substring(colIdx, closeIdx + 1); // include the >
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Strip color tags from a string.
|
||||||
|
*
|
||||||
|
* @param str
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@VisibleForTesting
|
||||||
|
static String stripColor(String str)
|
||||||
|
{
|
||||||
|
return str.replaceAll("(<col=[0-9a-f]+>|</col>)", "");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -131,6 +131,82 @@ public class ChatNotificationsPluginTest
|
|||||||
verify(messageNode).setValue("foo <colHIGHLIGHT>test<colNORMAL>. bar");
|
verify(messageNode).setValue("foo <colHIGHLIGHT>test<colNORMAL>. bar");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testColor()
|
||||||
|
{
|
||||||
|
when(config.highlightWordsString()).thenReturn("you. It");
|
||||||
|
|
||||||
|
String message = "Your dodgy necklace protects you. <col=ff0000>It has 1 charge left.</col>";
|
||||||
|
MessageNode messageNode = mock(MessageNode.class);
|
||||||
|
when(messageNode.getValue()).thenReturn(message);
|
||||||
|
|
||||||
|
ChatMessage chatMessage = new ChatMessage();
|
||||||
|
chatMessage.setType(ChatMessageType.PUBLICCHAT);
|
||||||
|
chatMessage.setMessageNode(messageNode);
|
||||||
|
|
||||||
|
chatNotificationsPlugin.startUp(); // load highlight config
|
||||||
|
chatNotificationsPlugin.onChatMessage(chatMessage);
|
||||||
|
|
||||||
|
verify(messageNode).setValue("Your dodgy necklace protects <colHIGHLIGHT>you. It<col=ff0000> has 1 charge left.</col>");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPreceedingColor()
|
||||||
|
{
|
||||||
|
when(config.highlightWordsString()).thenReturn("you. It");
|
||||||
|
|
||||||
|
String message = "Your dodgy <col=00ff00>necklace protects you. It has 1 charge left.</col>";
|
||||||
|
MessageNode messageNode = mock(MessageNode.class);
|
||||||
|
when(messageNode.getValue()).thenReturn(message);
|
||||||
|
|
||||||
|
ChatMessage chatMessage = new ChatMessage();
|
||||||
|
chatMessage.setType(ChatMessageType.PUBLICCHAT);
|
||||||
|
chatMessage.setMessageNode(messageNode);
|
||||||
|
|
||||||
|
chatNotificationsPlugin.startUp(); // load highlight config
|
||||||
|
chatNotificationsPlugin.onChatMessage(chatMessage);
|
||||||
|
|
||||||
|
verify(messageNode).setValue("Your dodgy <col=00ff00>necklace protects <colHIGHLIGHT>you. It<col=00ff00> has 1 charge left.</col>");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEmoji()
|
||||||
|
{
|
||||||
|
when(config.highlightWordsString()).thenReturn("test");
|
||||||
|
|
||||||
|
String message = "emoji test <img=29>";
|
||||||
|
MessageNode messageNode = mock(MessageNode.class);
|
||||||
|
when(messageNode.getValue()).thenReturn(message);
|
||||||
|
|
||||||
|
ChatMessage chatMessage = new ChatMessage();
|
||||||
|
chatMessage.setType(ChatMessageType.PUBLICCHAT);
|
||||||
|
chatMessage.setMessageNode(messageNode);
|
||||||
|
|
||||||
|
chatNotificationsPlugin.startUp(); // load highlight config
|
||||||
|
chatNotificationsPlugin.onChatMessage(chatMessage);
|
||||||
|
|
||||||
|
verify(messageNode).setValue("emoji <colHIGHLIGHT>test<colNORMAL> <img=29>");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNonMatchedColors()
|
||||||
|
{
|
||||||
|
when(config.highlightWordsString()).thenReturn("test");
|
||||||
|
|
||||||
|
String message = "<col=ff0000>color</col> test <img=29>";
|
||||||
|
MessageNode messageNode = mock(MessageNode.class);
|
||||||
|
when(messageNode.getValue()).thenReturn(message);
|
||||||
|
|
||||||
|
ChatMessage chatMessage = new ChatMessage();
|
||||||
|
chatMessage.setType(ChatMessageType.PUBLICCHAT);
|
||||||
|
chatMessage.setMessageNode(messageNode);
|
||||||
|
|
||||||
|
chatNotificationsPlugin.startUp(); // load highlight config
|
||||||
|
chatNotificationsPlugin.onChatMessage(chatMessage);
|
||||||
|
|
||||||
|
verify(messageNode).setValue("<col=ff0000>color</col> <colHIGHLIGHT>test<colNORMAL> <img=29>");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void highlightListTest()
|
public void highlightListTest()
|
||||||
{
|
{
|
||||||
@@ -144,4 +220,10 @@ public class ChatNotificationsPluginTest
|
|||||||
assertEquals("a", iterator.next());
|
assertEquals("a", iterator.next());
|
||||||
assertEquals("test", iterator.next());
|
assertEquals("test", iterator.next());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testStripColor()
|
||||||
|
{
|
||||||
|
assertEquals("you. It", ChatNotificationsPlugin.stripColor("you. <col=ff0000>It"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user