Support expandable block quote entities in MarkdownV2.

This commit is contained in:
levlam 2024-05-21 12:26:23 +03:00
parent 36ebd42a92
commit fa6ed08534
2 changed files with 50 additions and 3 deletions

View File

@ -2171,8 +2171,21 @@ Result<vector<MessageEntity>> parse_markdown_v2(string &text) {
// end of an entity
auto type = nested_entities.back().type;
if (c == '\n' && type != MessageEntity::Type::BlockQuote) {
return Status::Error(400, PSLICE() << "Can't find end of " << nested_entities.back().type
<< " entity at byte offset " << nested_entities.back().entity_byte_offset);
if (type != MessageEntity::Type::Spoiler || !(nested_entities.back().entity_byte_offset == i - 2 ||
(nested_entities.back().entity_byte_offset == i - 3 &&
result_size != 0 && text[result_size - 1] == '\r'))) {
return Status::Error(400, PSLICE() << "Can't find end of " << nested_entities.back().type
<< " entity at byte offset " << nested_entities.back().entity_byte_offset);
}
nested_entities.pop_back();
CHECK(!nested_entities.empty());
type = nested_entities.back().type;
if (type != MessageEntity::Type::BlockQuote) {
CHECK(type != MessageEntity::Type::Spoiler);
return Status::Error(400, PSLICE() << "Can't find end of " << nested_entities.back().type
<< " entity at byte offset " << nested_entities.back().entity_byte_offset);
}
type = MessageEntity::Type::ExpandableBlockQuote;
}
auto argument = std::move(nested_entities.back().argument);
UserId user_id;
@ -2247,6 +2260,7 @@ Result<vector<MessageEntity>> parse_markdown_v2(string &text) {
break;
}
case MessageEntity::Type::BlockQuote:
case MessageEntity::Type::ExpandableBlockQuote:
CHECK(have_blockquote);
have_blockquote = false;
text[result_size++] = text[i];
@ -2275,12 +2289,19 @@ Result<vector<MessageEntity>> parse_markdown_v2(string &text) {
}
if (have_blockquote) {
CHECK(!nested_entities.empty());
auto type = MessageEntity::Type::BlockQuote;
if (nested_entities.back().type == MessageEntity::Type::Spoiler &&
nested_entities.back().entity_byte_offset == text.size() - 2) {
nested_entities.pop_back();
CHECK(!nested_entities.empty());
type = MessageEntity::Type::ExpandableBlockQuote;
}
if (nested_entities.back().type == MessageEntity::Type::BlockQuote) {
have_blockquote = false;
auto entity_offset = nested_entities.back().entity_offset;
auto entity_length = utf16_offset - entity_offset;
if (entity_length != 0) {
entities.emplace_back(MessageEntity::Type::BlockQuote, entity_offset, entity_length);
entities.emplace_back(type, entity_offset, entity_length);
}
nested_entities.pop_back();
}

View File

@ -1430,6 +1430,10 @@ TEST(MessageEntities, parse_markdown) {
check_parse_markdown("🏟 🏟![👍](tg://emoji?test=1231&id=025)", "Invalid custom emoji identifier specified");
check_parse_markdown(">*b\n>ld \n>bo\nld*\nasd\ndef", "Can't find end of Bold entity at byte offset 1");
check_parse_markdown(">\n*a*>2", "Character '>' is reserved and must be escaped with the preceding '\\'");
check_parse_markdown(">asd\n>q||e||w||\n||asdad", "Can't find end of Spoiler entity at byte offset 16");
check_parse_markdown(">asd\n>q||ew\n||asdad", "Can't find end of Spoiler entity at byte offset 7");
check_parse_markdown(">asd\n>q||e||w__\n||asdad", "Can't find end of Underline entity at byte offset 13");
check_parse_markdown(">asd\n>q||e||w||a\n||asdad", "Can't find end of Spoiler entity at byte offset 13");
check_parse_markdown("", "", {});
check_parse_markdown("\\\\", "\\", {});
@ -1525,6 +1529,7 @@ TEST(MessageEntities, parse_markdown) {
{{td::MessageEntity::Type::BlockQuote, 0, 1}, {td::MessageEntity::Type::BlockQuote, 2, 1}});
check_parse_markdown(">\n**>2", "\n2",
{{td::MessageEntity::Type::BlockQuote, 0, 1}, {td::MessageEntity::Type::BlockQuote, 1, 1}});
check_parse_markdown(">**\n>2", "\n2", {{td::MessageEntity::Type::BlockQuote, 0, 2}});
// check_parse_markdown("*>abcd*", "abcd",
// {{td::MessageEntity::Type::BlockQuote, 0, 4}, {td::MessageEntity::Type::Bold, 0, 4}});
check_parse_markdown(">*abcd*", "abcd",
@ -1537,6 +1542,27 @@ TEST(MessageEntities, parse_markdown) {
{{td::MessageEntity::Type::BlockQuote, 0, 5}, {td::MessageEntity::Type::Bold, 0, 5}});
check_parse_markdown("abc\n>def\n>def\n\r>ghi2\njkl", "abc\ndef\ndef\n\rghi2\njkl",
{{td::MessageEntity::Type::BlockQuote, 4, 8}, {td::MessageEntity::Type::BlockQuote, 13, 5}});
check_parse_markdown(
">asd\n>q||e||w||\nasdad", "asd\nqew\nasdad",
{{td::MessageEntity::Type::ExpandableBlockQuote, 0, 8}, {td::MessageEntity::Type::Spoiler, 5, 1}});
check_parse_markdown(">asd\n>q||ew||\nasdad", "asd\nqew\nasdad",
{{td::MessageEntity::Type::BlockQuote, 0, 8}, {td::MessageEntity::Type::Spoiler, 5, 2}});
check_parse_markdown(
">asd\r\n>q||e||w||\r\nasdad", "asd\r\nqew\r\nasdad",
{{td::MessageEntity::Type::ExpandableBlockQuote, 0, 10}, {td::MessageEntity::Type::Spoiler, 6, 1}});
check_parse_markdown(">asd\r\n>q||ew||\r\nasdad", "asd\r\nqew\r\nasdad",
{{td::MessageEntity::Type::BlockQuote, 0, 10}, {td::MessageEntity::Type::Spoiler, 6, 2}});
check_parse_markdown(
">asd\r\n>q||e||w||\r\n", "asd\r\nqew\r\n",
{{td::MessageEntity::Type::ExpandableBlockQuote, 0, 10}, {td::MessageEntity::Type::Spoiler, 6, 1}});
check_parse_markdown(">asd\r\n>q||ew||\r\n", "asd\r\nqew\r\n",
{{td::MessageEntity::Type::BlockQuote, 0, 10}, {td::MessageEntity::Type::Spoiler, 6, 2}});
check_parse_markdown(
">asd\r\n>q||e||w||", "asd\r\nqew",
{{td::MessageEntity::Type::ExpandableBlockQuote, 0, 8}, {td::MessageEntity::Type::Spoiler, 6, 1}});
check_parse_markdown(">asd\r\n>q||ew||", "asd\r\nqew",
{{td::MessageEntity::Type::BlockQuote, 0, 8}, {td::MessageEntity::Type::Spoiler, 6, 2}});
check_parse_markdown(">||", "", {});
}
static void check_parse_markdown_v3(td::string text, td::vector<td::MessageEntity> entities,