Keep every line of a multi-line message in chat history
The text log has a message's line breaks in it, but history was read one line at a time, so every line after the first failed to parse and was dropped. A line that starts no entry of its own now continues the message before it, which also recovers what earlier versions wrote. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -175,13 +175,33 @@ public final class ChatLogStore {
|
|||||||
return entries;
|
return entries;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A message is written as it was sent, so one with line breaks spans several lines of the
|
||||||
|
* log: a line that starts no entry of its own continues the message before it.
|
||||||
|
*/
|
||||||
private static List<String> readTextMessages(LogFiles files, ChatLogScope scope) throws IOException {
|
private static List<String> readTextMessages(LogFiles files, ChatLogScope scope) throws IOException {
|
||||||
if (!Files.isRegularFile(files.txt)) return Collections.emptyList();
|
if (!Files.isRegularFile(files.txt)) return Collections.emptyList();
|
||||||
List<String> entries = new ArrayList<>();
|
List<String> entries = new ArrayList<>();
|
||||||
|
Matcher message = null;
|
||||||
|
StringBuilder text = new StringBuilder();
|
||||||
for (String line : Files.readAllLines(files.txt, StandardCharsets.UTF_8)) {
|
for (String line : Files.readAllLines(files.txt, StandardCharsets.UTF_8)) {
|
||||||
String entry = textLineToHtml(line, scope);
|
Matcher m = TEXT_MESSAGE.matcher(line);
|
||||||
if (entry != null) entries.add(entry);
|
boolean begin = line.startsWith("*** ");
|
||||||
|
if (!m.matches() && !begin) {
|
||||||
|
if (message != null) text.append('\n').append(line);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
if (message != null) entries.add(messageLineHtml(message, text, scope));
|
||||||
|
message = null;
|
||||||
|
if (begin) {
|
||||||
|
entries.add(beginLineHtml(line));
|
||||||
|
} else {
|
||||||
|
message = m;
|
||||||
|
text.setLength(0);
|
||||||
|
text.append(m.group(3));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (message != null) entries.add(messageLineHtml(message, text, scope));
|
||||||
return entries;
|
return entries;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -190,14 +210,12 @@ public final class ChatLogStore {
|
|||||||
return new ArrayList<>(entries.subList(entries.size() - limit, entries.size()));
|
return new ArrayList<>(entries.subList(entries.size() - limit, entries.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String textLineToHtml(String line, ChatLogScope scope) {
|
private static String beginLineHtml(String line) {
|
||||||
if (line == null || line.isBlank()) return null;
|
|
||||||
if (line.startsWith("*** ")) {
|
|
||||||
return "<div class=\"TextMessage_BeginHistory\"><span class=\"Body\">"
|
return "<div class=\"TextMessage_BeginHistory\"><span class=\"Body\">"
|
||||||
+ BBCode.escape(line) + "</span></div>";
|
+ BBCode.escape(line) + "</span></div>";
|
||||||
}
|
}
|
||||||
Matcher m = TEXT_MESSAGE.matcher(line);
|
|
||||||
if (!m.matches()) return null;
|
private static String messageLineHtml(Matcher m, CharSequence text, ChatLogScope scope) {
|
||||||
String target = switch (scope) {
|
String target = switch (scope) {
|
||||||
case PRIVATE -> "Private";
|
case PRIVATE -> "Private";
|
||||||
case CHANNEL -> "Channel";
|
case CHANNEL -> "Channel";
|
||||||
@@ -206,7 +224,8 @@ public final class ChatLogStore {
|
|||||||
return "<div class=\"TextMessage_Message Incoming Neutral " + target + "\"><span class=\"Body\">"
|
return "<div class=\"TextMessage_Message Incoming Neutral " + target + "\"><span class=\"Body\">"
|
||||||
+ "<span class=\"TextMessage_Time\"><" + m.group(1) + "></span> "
|
+ "<span class=\"TextMessage_Time\"><" + m.group(1) + "></span> "
|
||||||
+ "<span class=\"TextMessage_UserLink\">"" + BBCode.escape(m.group(2)) + ""</span>: "
|
+ "<span class=\"TextMessage_UserLink\">"" + BBCode.escape(m.group(2)) + ""</span>: "
|
||||||
+ "<span class=\"TextMessage_Text\">" + BBCode.toHtml(m.group(3)) + "</span></span></div>";
|
+ "<span class=\"TextMessage_Text\">" + BBCode.toHtml(text.toString().stripTrailing())
|
||||||
|
+ "</span></span></div>";
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String beginHtml(String kind, LocalDateTime timestamp) {
|
private static String beginHtml(String kind, LocalDateTime timestamp) {
|
||||||
|
|||||||
@@ -68,4 +68,16 @@ class ChatLogStoreTest {
|
|||||||
assertTrue(capped.truncated());
|
assertTrue(capped.truncated());
|
||||||
assertTrue(capped.entries().get(9).contains("filler " + (ChatLogStore.HISTORY_LIMIT - 1)));
|
assertTrue(capped.entries().get(9).contains("filler " + (ChatLogStore.HISTORY_LIMIT - 1)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void readsAMessageWithLineBreaksBackWhole() throws Exception {
|
||||||
|
ChatLogStore logs = new ChatLogStore(temp, "+Tyg2JtxE8vRNZp+JiUBnmBh0MY=");
|
||||||
|
logs.appendMessage(ChatLogScope.CHANNEL, false, 5, "uid", "alice", "first line\n\nthird line");
|
||||||
|
logs.appendMessage(ChatLogScope.CHANNEL, false, 5, "uid", "bob", "reply");
|
||||||
|
|
||||||
|
List<String> history = logs.channelHtmlHistory();
|
||||||
|
assertEquals(2, history.size());
|
||||||
|
assertTrue(history.get(0).contains("first line<br><br>third line"), history.get(0));
|
||||||
|
assertTrue(history.get(1).contains("reply"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user