Added support for custom indexes of links in Ui::String::Text.

This commit is contained in:
23rd 2022-02-03 23:08:09 +03:00
parent 8618812fd6
commit 7e1effeeeb
3 changed files with 85 additions and 23 deletions

View file

@ -178,19 +178,21 @@ private:
class StartedEntity {
public:
enum class Type {
Flags,
Link,
IndexedLink,
Spoiler,
};
explicit StartedEntity(TextBlockFlags flags);
explicit StartedEntity(uint16 index, bool isLnk = true);
explicit StartedEntity(uint16 index, Type type);
std::optional<TextBlockFlags> flags() const;
std::optional<uint16> lnkIndex() const;
std::optional<uint16> spoilerIndex() const;
private:
enum class Type {
Flags,
Link,
Spoiler,
};
const int _value = 0;
const Type _type;
@ -222,6 +224,8 @@ private:
bool isInvalidEntity(const EntityInText &entity) const;
bool isLinkEntity(const EntityInText &entity) const;
bool processCustomIndex(uint16 index);
void parse(const TextParseOptions &options);
void computeLinkText(
const QString &linkData,
@ -241,6 +245,8 @@ private:
const QFixed _stopAfterWidth; // summary width of all added words
const bool _checkTilde = false; // do we need a special text block for tilde symbol
std::vector<uint16> _linksIndexes;
std::vector<EntityLinkData> _links;
std::vector<EntityLinkData> _spoilers;
std::vector<EntityLinkData> _monos;
@ -276,9 +282,9 @@ Parser::StartedEntity::StartedEntity(TextBlockFlags flags)
Expects(_value >= 0 && _value < int(kStringLinkIndexShift));
}
Parser::StartedEntity::StartedEntity(uint16 index, bool isLnk)
Parser::StartedEntity::StartedEntity(uint16 index, Type type)
: _value(index)
, _type(isLnk ? Type::Link : Type::Spoiler) {
, _type(type) {
Expects((_type == Type::Link)
? (_value >= kStringLinkIndexShift)
: (_value < kStringLinkIndexShift));
@ -292,7 +298,8 @@ std::optional<TextBlockFlags> Parser::StartedEntity::flags() const {
}
std::optional<uint16> Parser::StartedEntity::lnkIndex() const {
if (_value >= int(kStringLinkIndexShift) && (_type == Type::Link)) {
if ((_value < int(kStringLinkIndexShift) && (_type == Type::IndexedLink))
|| (_value >= int(kStringLinkIndexShift) && (_type == Type::Link))) {
return uint16(_value);
}
return std::nullopt;
@ -515,13 +522,18 @@ bool Parser::checkEntities() {
pushComplexUrl();
}
using Type = StartedEntity::Type;
if (link.type != EntityType::Invalid) {
createBlock();
_links.push_back(link);
_lnkIndex = kStringLinkIndexShift + _links.size();
_startedEntities[entityEnd].emplace_back(_lnkIndex);
const auto tempIndex = _links.size();
const auto useCustom = processCustomIndex(tempIndex);
_lnkIndex = tempIndex + (useCustom ? 0 : kStringLinkIndexShift);
_startedEntities[entityEnd].emplace_back(
_lnkIndex,
useCustom ? Type::IndexedLink : Type::Link);
} else if (flags) {
if (!(_flags & flags)) {
createBlock();
@ -538,7 +550,9 @@ bool Parser::checkEntities() {
});
_spoilerIndex = _spoilers.size();
_startedEntities[entityEnd].emplace_back(_spoilerIndex, false);
_startedEntities[entityEnd].emplace_back(
_spoilerIndex,
Type::Spoiler);
}
++_waitingEntity;
@ -546,6 +560,22 @@ bool Parser::checkEntities() {
return true;
}
bool Parser::processCustomIndex(uint16 index) {
auto &url = _links[index - 1].data;
if (url.isEmpty()) {
return false;
}
if (url.startsWith("internal:index") && url.back().isDigit()) {
const auto customIndex = uint16(url.back().unicode() - '0');
// if (customIndex != index) {
url = QString();
_linksIndexes.push_back(customIndex);
return true;
// }
}
return false;
}
void Parser::skipPassedEntities() {
while (_waitingEntity != _entitiesEnd
&& _start + _waitingEntity->offset() + _waitingEntity->length() <= _ptr) {
@ -737,11 +767,17 @@ void Parser::trimSourceRange() {
void Parser::finalize(const TextParseOptions &options) {
_t->_links.resize(_maxLnkIndex + _maxShiftedLnkIndex);
auto counterCustomIndex = uint16(0);
auto currentIndex = uint16(0); // Current the latest index of _t->_links.
struct {
uint16 mono = 0;
uint16 lnk = 0;
} lastHandlerIndex;
const auto avoidIntersectionsWithCustom = [&] {
while (ranges::contains(_linksIndexes, currentIndex)) {
currentIndex++;
}
};
for (auto &block : _t->_blocks) {
const auto spoilerIndex = block->spoilerIndex();
if (spoilerIndex && (_t->_spoilers.size() < spoilerIndex)) {
@ -752,6 +788,7 @@ void Parser::finalize(const TextParseOptions &options) {
_t->setSpoiler(spoilerIndex, std::move(handler));
}
const auto shiftedIndex = block->lnkIndex();
auto useCustomIndex = false;
if (shiftedIndex <= kStringLinkIndexShift) {
if (IsMono(block->flags()) && shiftedIndex) {
const auto monoIndex = shiftedIndex;
@ -762,6 +799,7 @@ void Parser::finalize(const TextParseOptions &options) {
} else {
currentIndex++;
}
avoidIntersectionsWithCustom();
block->setLnkIndex(currentIndex);
const auto handler = Integration::Instance().createLinkHandler(
_monos[monoIndex - 1],
@ -771,24 +809,38 @@ void Parser::finalize(const TextParseOptions &options) {
_t->setLink(currentIndex, handler);
}
lastHandlerIndex.mono = monoIndex;
continue;
} else if (shiftedIndex) {
useCustomIndex = true;
} else {
continue;
}
continue;
}
const auto realIndex = (shiftedIndex - kStringLinkIndexShift);
const auto usedIndex = [&] {
return useCustomIndex
? _linksIndexes[counterCustomIndex - 1]
: currentIndex;
};
const auto realIndex = useCustomIndex
? shiftedIndex
: (shiftedIndex - kStringLinkIndexShift);
if (lastHandlerIndex.lnk == realIndex) {
block->setLnkIndex(currentIndex);
block->setLnkIndex(usedIndex());
continue; // Optimization.
} else {
currentIndex++;
(useCustomIndex ? counterCustomIndex : currentIndex)++;
}
block->setLnkIndex(currentIndex);
if (!useCustomIndex) {
avoidIntersectionsWithCustom();
}
block->setLnkIndex(usedIndex());
_t->_links.resize(currentIndex);
_t->_links.resize(std::max(usedIndex(), uint16(_t->_links.size())));
const auto handler = Integration::Instance().createLinkHandler(
_links[realIndex - 1],
_context);
if (handler) {
_t->setLink(currentIndex, handler);
_t->setLink(usedIndex(), handler);
}
lastHandlerIndex.lnk = realIndex;
}

View file

@ -42,14 +42,22 @@ TextWithEntities Link(const QString &text, const QString &url) {
return WithSingleEntity(text, EntityType::CustomUrl, url);
}
TextWithEntities Link(const QString &text, int index) {
Expects(index > 0 && index < 10);
return Link(text, QString("internal:index") + QChar('0' + index));
}
TextWithEntities PlainLink(const QString &text) {
return WithSingleEntity(text, EntityType::PlainLink);
}
TextWithEntities Wrapped(TextWithEntities text, EntityType type) {
TextWithEntities Wrapped(
TextWithEntities text,
EntityType type,
const QString &data) {
text.entities.insert(
text.entities.begin(),
{ type, 0, int(text.text.size()), {} });
{ type, 0, int(text.text.size()), data });
return text;
}

View file

@ -30,10 +30,12 @@ inline constexpr auto Upper = details::ToUpperType{};
[[nodiscard]] TextWithEntities Link(
const QString &text,
const QString &url = "internal:action");
[[nodiscard]] TextWithEntities Link(const QString &text, int index);
[[nodiscard]] TextWithEntities PlainLink(const QString &text);
[[nodiscard]] TextWithEntities Wrapped(
TextWithEntities text,
EntityType type);
EntityType type,
const QString &data = QString());
[[nodiscard]] TextWithEntities RichLangValue(const QString &text);
[[nodiscard]] inline TextWithEntities WithEntities(const QString &text) {
return { text };