Track Ui::Text::String modifications on parse.
This commit is contained in:
parent
84cc457af9
commit
45ffbdeef9
5 changed files with 45 additions and 32 deletions
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue