Track Ui::Text::String modifications on parse.

This commit is contained in:
John Preston 2023-10-11 21:49:00 +04:00
parent 84cc457af9
commit 45ffbdeef9
5 changed files with 45 additions and 32 deletions

View file

@ -293,6 +293,9 @@ public:
[[nodiscard]] OnlyCustomEmoji toOnlyCustomEmoji() const;
[[nodiscard]] bool hasNotEmojiAndSpaces() const;
[[nodiscard]] const base::flat_map<int, int> &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<int, int> _modifications;
const style::TextStyle *_st = nullptr;
TextBlocks _blocks;

View file

@ -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;
}

View file

@ -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<EntityInText>;
using EntitiesInText = QVector<EntityInText>;
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;

View file

@ -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(

View file

@ -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.