chat notifications: fix matching messages with color

This commit is contained in:
Adam
2019-09-04 15:25:33 -04:00
parent abe7c40852
commit 58c5017ae9
2 changed files with 161 additions and 2 deletions

View File

@@ -25,6 +25,7 @@
*/
package net.runelite.client.plugins.chatnotifications;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Strings;
import com.google.inject.Provides;
import java.util.List;
@@ -115,7 +116,7 @@ public class ChatNotificationsPlugin extends Plugin
List<String> items = Text.fromCSV(config.highlightWordsString());
String joined = items.stream()
.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("|"));
// To match <word> \b doesn't work due to <> not being in \w,
// so match \b or \s
@@ -184,7 +185,26 @@ public class ChatNotificationsPlugin extends Plugin
while (matcher.find())
{
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;
found = true;
}
@@ -228,4 +248,61 @@ public class ChatNotificationsPlugin extends Plugin
String notification = stringBuilder.toString();
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>)", "");
}
}

View File

@@ -131,6 +131,82 @@ public class ChatNotificationsPluginTest
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
public void highlightListTest()
{
@@ -144,4 +220,10 @@ public class ChatNotificationsPluginTest
assertEquals("a", iterator.next());
assertEquals("test", iterator.next());
}
@Test
public void testStripColor()
{
assertEquals("you. It", ChatNotificationsPlugin.stripColor("you. <col=ff0000>It"));
}
}