| author | Stephen Paul Weber
<singpolyma@singpolyma.net> 2026-09-01 19:09:31 UTC |
| committer | Stephen Paul Weber
<singpolyma@singpolyma.net> 2026-09-01 20:50:53 UTC |
| parent | 34988414c21c30ebec9ddb29d5f183ba8ecd30a3 |
| borogove/ChatMessage.hx | +7 | -3 |
| test/TestChatMessage.hx | +72 | -0 |
diff --git a/borogove/ChatMessage.hx b/borogove/ChatMessage.hx index 548447f..904aa71 100644 --- a/borogove/ChatMessage.hx +++ b/borogove/ChatMessage.hx @@ -630,18 +630,22 @@ class ChatMessage { final replyId = replyToM.getReplyId(); if (body != null) { final lines = replyToM.text?.split("\n") ?? []; + final reaction = EmojiUtil.isEmoji(StringTools.trim(body)) ? StringTools.trim(body.replace("\u{fe0f}", "")) : null; var quoteText = ""; for (line in lines) { if (!~/^(?:> ?){3,}/.match(line)) { if (line.charAt(0) == ">") { - quoteText += ">" + line + "\n"; + if (reaction == null) quoteText += ">" + line + "\n"; } else { - quoteText += "> " + line + "\n"; + quoteText += "> " + line; + if (reaction != null) break; + quoteText += "\n"; } } } + if (reaction != null && lines.length > 1) quoteText += "…"; + if (reaction != null) quoteText += "\n"; if (quoteText != "") quoteText += "\n"; - final reaction = EmojiUtil.isEmoji(StringTools.trim(body)) ? StringTools.trim(body.replace("\u{fe0f}", "")) : null; body = quoteText + body; if (replyId != null) { final codepoints = StringUtil.codepointArray(quoteText); diff --git a/test/TestChatMessage.hx b/test/TestChatMessage.hx index e08794d..321809d 100644 --- a/test/TestChatMessage.hx +++ b/test/TestChatMessage.hx @@ -172,4 +172,76 @@ class TestChatMessage extends utest.Test { Assert.fail("Expected SubjectStanza"); } } + + public function testReactionFallbackShorterContext() { + // Build a parent message with multiple lines + final parentBuilder = new borogove.ChatMessageBuilder(); + parentBuilder.localId = "parent-id"; + parentBuilder.from = JID.parse("alice@example.com"); + parentBuilder.to = JID.parse("bob@example.com"); + parentBuilder.senderId = "alice@example.com"; + parentBuilder.setBody(borogove.Html.text("line one\nline two\nline three")); + final parent = parentBuilder.build(); + + // Reply with an emoji (reaction) + final reply = parent.reply(); + reply.from = JID.parse("bob@example.com"); + reply.to = JID.parse("alice@example.com"); + reply.senderId = "bob@example.com"; + reply.localId = "reply-id"; + reply.setBody(borogove.Html.text("👍")); + final replyMsg = reply.build(); + final stanza = replyMsg.asStanza(); + final body = stanza.getChildText("body"); + // Reaction should only quote the first line + Assert.equals("> line one…\n\n👍", body); + } + + public function testNormalReplyQuotesAllLines() { + // Build a parent message with multiple lines + final parentBuilder = new borogove.ChatMessageBuilder(); + parentBuilder.localId = "parent-id"; + parentBuilder.from = JID.parse("alice@example.com"); + parentBuilder.to = JID.parse("bob@example.com"); + parentBuilder.senderId = "alice@example.com"; + parentBuilder.setBody(borogove.Html.text("line one\nline two\nline three")); + final parent = parentBuilder.build(); + + // Reply with normal text + final reply = parent.reply(); + reply.from = JID.parse("bob@example.com"); + reply.to = JID.parse("alice@example.com"); + reply.senderId = "bob@example.com"; + reply.localId = "reply-id"; + reply.setBody(borogove.Html.text("ok sure")); + final replyMsg = reply.build(); + final stanza = replyMsg.asStanza(); + final body = stanza.getChildText("body"); + // Normal reply should quote all lines + Assert.equals("> line one\n> line two\n> line three\n\nok sure", body); + } + + public function testReactionFallbackSkipsNestedQuotes() { + // Build a parent message that itself contains a quote and regular text + final parentBuilder = new borogove.ChatMessageBuilder(); + parentBuilder.localId = "parent-id"; + parentBuilder.from = JID.parse("alice@example.com"); + parentBuilder.to = JID.parse("bob@example.com"); + parentBuilder.senderId = "alice@example.com"; + parentBuilder.setBody(borogove.Html.text("> quoted line\nactual text\nmore text")); + final parent = parentBuilder.build(); + + // Reply with an emoji (reaction) + final reply = parent.reply(); + reply.from = JID.parse("bob@example.com"); + reply.to = JID.parse("alice@example.com"); + reply.senderId = "bob@example.com"; + reply.localId = "reply-id"; + reply.setBody(borogove.Html.text("❤️")); + final replyMsg = reply.build(); + final stanza = replyMsg.asStanza(); + final body = stanza.getChildText("body"); + // Reaction should skip the already-quoted line and only quote the first non-quoted line + Assert.equals("> actual text…\n\n❤️", body); + } }