From 45ffbdeef992207065b320d1aabd71fc4186722f Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 11 Oct 2023 21:49:00 +0400 Subject: [PATCH] Track Ui::Text::String modifications on parse. --- ui/text/text.h | 4 ++++ ui/text/text_entity.cpp | 2 +- ui/text/text_entity.h | 46 ++++++++++++++++++++--------------------- ui/text/text_parser.cpp | 23 +++++++++++++++------ ui/text/text_parser.h | 2 +- 5 files changed, 45 insertions(+), 32 deletions(-) diff --git a/ui/text/text.h b/ui/text/text.h index 2b32bb8..a627a56 100644 --- a/ui/text/text.h +++ b/ui/text/text.h @@ -293,6 +293,9 @@ public: [[nodiscard]] OnlyCustomEmoji toOnlyCustomEmoji() const; [[nodiscard]] bool hasNotEmojiAndSpaces() const; + [[nodiscard]] const base::flat_map &modifications() const { + return _modifications; + } [[nodiscard]] const style::TextStyle *style() const { return _st; @@ -350,6 +353,7 @@ private: bool _hasNotEmojiAndSpaces : 1 = false; QString _text; + base::flat_map _modifications; const style::TextStyle *_st = nullptr; TextBlocks _blocks; diff --git a/ui/text/text_entity.cpp b/ui/text/text_entity.cpp index c2d48ef..9d25dd6 100644 --- a/ui/text/text_entity.cpp +++ b/ui/text/text_entity.cpp @@ -1890,7 +1890,7 @@ void Trim(TextWithEntities &result) { } int SerializeTagsSize(const TextWithTags::Tags &tags) { - auto result = qint32(0); + auto result = int(sizeof(qint32)); // QByteArray size if (tags.isEmpty()) { return result; } diff --git a/ui/text/text_entity.h b/ui/text/text_entity.h index 2c919e2..2aa8385 100644 --- a/ui/text/text_entity.h +++ b/ui/text/text_entity.h @@ -50,10 +50,17 @@ struct EntityLinkData { QString data; EntityType type = EntityType::Invalid; EntityLinkShown shown = EntityLinkShown::Full; + + friend inline auto operator<=>( + const EntityLinkData &, + const EntityLinkData &) = default; + friend inline bool operator==( + const EntityLinkData &, + const EntityLinkData &) = default; }; class EntityInText; -using EntitiesInText = QList; +using EntitiesInText = QVector; class EntityInText { public: @@ -113,6 +120,13 @@ public: return type() != EntityType::Invalid; } + friend inline auto operator<=>( + const EntityInText &, + const EntityInText &) = default; + friend inline bool operator==( + const EntityInText &, + const EntityInText &) = default; + private: EntityType _type = EntityType::Invalid; int _offset = 0; @@ -121,17 +135,6 @@ private: }; -inline bool operator==(const EntityInText &a, const EntityInText &b) { - return (a.type() == b.type()) - && (a.offset() == b.offset()) - && (a.length() == b.length()) - && (a.data() == b.data()); -} - -inline bool operator!=(const EntityInText &a, const EntityInText &b) { - return !(a == b); -} - struct TextWithEntities { QString text; EntitiesInText entities; @@ -182,20 +185,15 @@ struct TextWithEntities { result.text = simple; return result; } + + friend inline auto operator<=>( + const TextWithEntities &, + const TextWithEntities &) = default; + friend inline bool operator==( + const TextWithEntities &, + const TextWithEntities &) = default; }; -inline bool operator==( - const TextWithEntities &a, - const TextWithEntities &b) { - return (a.text == b.text) && (a.entities == b.entities); -} - -inline bool operator!=( - const TextWithEntities &a, - const TextWithEntities &b) { - return !(a == b); -} - struct TextForMimeData { QString expanded; TextWithEntities rich; diff --git a/ui/text/text_parser.cpp b/ui/text/text_parser.cpp index 79a0e45..72ef261 100644 --- a/ui/text/text_parser.cpp +++ b/ui/text/text_parser.cpp @@ -182,6 +182,7 @@ void Parser::createBlock(int32 skipBack) { if (_newlineAwaited) { _newlineAwaited = false; if (!newline) { + ++_t->_modifications[_blockStart]; _t->_text.insert(_blockStart, QChar::LineFeed); createBlock(skipBack - length); } @@ -220,20 +221,23 @@ void Parser::createBlock(int32 skipBack) { blockCreated(); } -void Parser::createNewlineBlock() { - createBlock(); +void Parser::createNewlineBlock(bool fromOriginalText) { + if (!fromOriginalText) { + ++_t->_modifications[_t->_text.size()]; + } _t->_text.push_back(QChar::LineFeed); _allowDiacritic = false; createBlock(); } void Parser::ensureAtNewline() { + createBlock(); const auto lastType = _t->_blocks.empty() ? TextBlockType::Newline : _t->_blocks.back()->type(); if (lastType != TextBlockType::Newline) { auto saved = base::take(_customEmojiData); - createNewlineBlock(); + createNewlineBlock(false); _customEmojiData = base::take(saved); } } @@ -335,7 +339,6 @@ bool Parser::checkEntities() { flags = TextBlockFlag::Code; } else { flags = TextBlockFlag::Pre; - createBlock(); ensureAtNewline(); } const auto text = QString(entityBegin, entityLength); @@ -352,7 +355,6 @@ bool Parser::checkEntities() { } } else if (entityType == EntityType::Blockquote) { flags = TextBlockFlag::Blockquote; - createBlock(); ensureAtNewline(); } else if (entityType == EntityType::Url || entityType == EntityType::Email @@ -498,6 +500,7 @@ void Parser::parseCurrentChar() { } if (skip) { + --_t->_modifications[_t->_text.size()]; _ch = 0; _allowDiacritic = false; } else { @@ -513,7 +516,8 @@ void Parser::parseCurrentChar() { } } if (isNewLine) { - createNewlineBlock(); + createBlock(); + createNewlineBlock(true); } else if (replaceWithSpace) { _t->_text.push_back(QChar::Space); _allowDiacritic = false; @@ -545,6 +549,7 @@ void Parser::parseEmojiFromCurrent() { Assert(!_t->_text.isEmpty()); const auto last = _t->_text[_t->_text.size() - 1]; if (last.unicode() != Emoji::kPostfix) { + ++_t->_modifications[_t->_text.size()]; _t->_text.push_back(QChar(Emoji::kPostfix)); ++len; } @@ -579,8 +584,13 @@ void Parser::parse(const TextParseOptions &options) { trimSourceRange(); _t->_text.resize(0); + _t->_modifications = {}; _t->_text.reserve(_end - _ptr); + if (_ptr > _start) { + _t->_modifications[0] = -(_ptr - _start); + } + for (; _ptr <= _end; ++_ptr) { while (checkEntities()) { } @@ -758,6 +768,7 @@ void Parser::finalize(const TextParseOptions &options) { _t->_links.squeeze(); _t->_blocks.shrink_to_fit(); _t->_text.squeeze(); + _t->_modifications.shrink_to_fit(); } void Parser::computeLinkText( diff --git a/ui/text/text_parser.h b/ui/text/text_parser.h index f50e452..d844edf 100644 --- a/ui/text/text_parser.h +++ b/ui/text/text_parser.h @@ -56,7 +56,7 @@ private: void trimSourceRange(); void blockCreated(); void createBlock(int32 skipBack = 0); - void createNewlineBlock(); + void createNewlineBlock(bool fromOriginalText); void ensureAtNewline(); // Returns true if at least one entity was parsed in the current position.