Added new entity type for plain non-interactive links.

Increased size of the block flags by two bits.
Added a text utility to wrap a simple text with plain links.
Added a new flag to specify parsing of plain links.
This commit is contained in:
23rd 2021-12-29 18:27:23 +03:00
parent 8e999fe8fb
commit 745ce34dd5
6 changed files with 45 additions and 26 deletions

View file

@ -77,7 +77,9 @@ TextWithEntities PrepareRichFromRich(
const TextParseOptions &options) { const TextParseOptions &options) {
auto result = text; auto result = text;
const auto &preparsed = text.entities; const auto &preparsed = text.entities;
if ((options.flags & TextParseLinks) && !preparsed.isEmpty()) { const bool parseLinks = (options.flags & TextParseLinks);
const bool parsePlainLinks = (options.flags & TextParsePlainLinks);
if (!preparsed.isEmpty() && (parseLinks || parsePlainLinks)) {
bool parseMentions = (options.flags & TextParseMentions); bool parseMentions = (options.flags & TextParseMentions);
bool parseHashtags = (options.flags & TextParseHashtags); bool parseHashtags = (options.flags & TextParseHashtags);
bool parseBotCommands = (options.flags & TextParseBotCommands); bool parseBotCommands = (options.flags & TextParseBotCommands);
@ -91,6 +93,12 @@ TextWithEntities PrepareRichFromRich(
if (((type == EntityType::Mention || type == EntityType::MentionName) && !parseMentions) || if (((type == EntityType::Mention || type == EntityType::MentionName) && !parseMentions) ||
(type == EntityType::Hashtag && !parseHashtags) || (type == EntityType::Hashtag && !parseHashtags) ||
(type == EntityType::Cashtag && !parseHashtags) || (type == EntityType::Cashtag && !parseHashtags) ||
(type == EntityType::PlainLink
&& !parsePlainLinks
&& !parseMarkdown) ||
(!parseLinks
&& (type == EntityType::Url
|| type == EntityType::CustomUrl)) ||
(type == EntityType::BotCommand && !parseBotCommands) || // #TODO entities (type == EntityType::BotCommand && !parseBotCommands) || // #TODO entities
(!parseMarkdown && (type == EntityType::Bold (!parseMarkdown && (type == EntityType::Bold
|| type == EntityType::Semibold || type == EntityType::Semibold
@ -601,6 +609,8 @@ bool Parser::checkEntities() {
flags = TextBlockFItalic; flags = TextBlockFItalic;
} else if (entityType == EntityType::Underline) { } else if (entityType == EntityType::Underline) {
flags = TextBlockFUnderline; flags = TextBlockFUnderline;
} else if (entityType == EntityType::PlainLink) {
flags = TextBlockFPlainLink;
} else if (entityType == EntityType::StrikeOut) { } else if (entityType == EntityType::StrikeOut) {
flags = TextBlockFStrikeOut; flags = TextBlockFStrikeOut;
} else if (entityType == EntityType::Code) { // #TODO entities } else if (entityType == EntityType::Code) { // #TODO entities
@ -2880,7 +2890,7 @@ private:
} else { } else {
_background = {}; _background = {};
} }
if (block->lnkIndex()) { if (block->lnkIndex() || (block->flags() & TextBlockFPlainLink)) {
_currentPen = &_textPalette->linkFg->p; _currentPen = &_textPalette->linkFg->p;
_currentPenSelected = &_textPalette->selectLinkFg->p; _currentPenSelected = &_textPalette->selectLinkFg->p;
} else if ((block->flags() & TextBlockFCode) || (block->flags() & TextBlockFPre)) { } else if ((block->flags() & TextBlockFCode) || (block->flags() & TextBlockFPre)) {
@ -3576,6 +3586,7 @@ TextForMimeData String::toText(
{ TextBlockFBold, EntityType::Bold }, { TextBlockFBold, EntityType::Bold },
{ TextBlockFSemibold, EntityType::Semibold }, { TextBlockFSemibold, EntityType::Semibold },
{ TextBlockFUnderline, EntityType::Underline }, { TextBlockFUnderline, EntityType::Underline },
{ TextBlockFPlainLink, EntityType::PlainLink },
{ TextBlockFStrikeOut, EntityType::StrikeOut }, { TextBlockFStrikeOut, EntityType::StrikeOut },
{ TextBlockFCode, EntityType::Code }, // #TODO entities { TextBlockFCode, EntityType::Code }, // #TODO entities
{ TextBlockFPre, EntityType::Pre }, { TextBlockFPre, EntityType::Pre },

View file

@ -345,11 +345,11 @@ AbstractBlock::AbstractBlock(
const QString &str, const QString &str,
uint16 from, uint16 from,
uint16 length, uint16 length,
uchar flags, uint16 flags,
uint16 lnkIndex, uint16 lnkIndex,
uint16 spoilerIndex) uint16 spoilerIndex)
: _from(from) : _from(from)
, _flags((flags & 0xFF) | ((lnkIndex & 0xFFFF) << 12)) , _flags((flags & 0b1111111111) | ((lnkIndex & 0xFFFF) << 14))
, _spoilerIndex(spoilerIndex) { , _spoilerIndex(spoilerIndex) {
} }
@ -374,11 +374,11 @@ QFixed AbstractBlock::f_rpadding() const {
} }
uint16 AbstractBlock::lnkIndex() const { uint16 AbstractBlock::lnkIndex() const {
return (_flags >> 12) & 0xFFFF; return (_flags >> 14) & 0xFFFF;
} }
void AbstractBlock::setLnkIndex(uint16 lnkIndex) { void AbstractBlock::setLnkIndex(uint16 lnkIndex) {
_flags = (_flags & ~(0xFFFF << 12)) | (lnkIndex << 12); _flags = (_flags & ~(0xFFFF << 14)) | (lnkIndex << 14);
} }
uint16 AbstractBlock::spoilerIndex() const { uint16 AbstractBlock::spoilerIndex() const {
@ -390,11 +390,11 @@ void AbstractBlock::setSpoilerIndex(uint16 spoilerIndex) {
} }
TextBlockType AbstractBlock::type() const { TextBlockType AbstractBlock::type() const {
return TextBlockType((_flags >> 8) & 0x0F); return TextBlockType((_flags >> 10) & 0x0F);
} }
int32 AbstractBlock::flags() const { int32 AbstractBlock::flags() const {
return (_flags & 0xFFF); return (_flags & 0b1111111111);
} }
QFixed AbstractBlock::f_rbearing() const { QFixed AbstractBlock::f_rbearing() const {
@ -409,11 +409,11 @@ TextBlock::TextBlock(
QFixed minResizeWidth, QFixed minResizeWidth,
uint16 from, uint16 from,
uint16 length, uint16 length,
uchar flags, uint16 flags,
uint16 lnkIndex, uint16 lnkIndex,
uint16 spoilerIndex) uint16 spoilerIndex)
: AbstractBlock(font, str, from, length, flags, lnkIndex, spoilerIndex) { : AbstractBlock(font, str, from, length, flags, lnkIndex, spoilerIndex) {
_flags |= ((TextBlockTText & 0x0F) << 8); _flags |= ((TextBlockTText & 0x0F) << 10);
if (length) { if (length) {
style::font blockFont = font; style::font blockFont = font;
if (!flags && lnkIndex) { if (!flags && lnkIndex) {
@ -455,13 +455,13 @@ EmojiBlock::EmojiBlock(
const QString &str, const QString &str,
uint16 from, uint16 from,
uint16 length, uint16 length,
uchar flags, uint16 flags,
uint16 lnkIndex, uint16 lnkIndex,
uint16 spoilerIndex, uint16 spoilerIndex,
EmojiPtr emoji) EmojiPtr emoji)
: AbstractBlock(font, str, from, length, flags, lnkIndex, spoilerIndex) : AbstractBlock(font, str, from, length, flags, lnkIndex, spoilerIndex)
, _emoji(emoji) { , _emoji(emoji) {
_flags |= ((TextBlockTEmoji & 0x0F) << 8); _flags |= ((TextBlockTEmoji & 0x0F) << 10);
_width = int(st::emojiSize + 2 * st::emojiPadding); _width = int(st::emojiSize + 2 * st::emojiPadding);
_rpadding = 0; _rpadding = 0;
for (auto i = length; i != 0;) { for (auto i = length; i != 0;) {
@ -479,11 +479,11 @@ NewlineBlock::NewlineBlock(
const QString &str, const QString &str,
uint16 from, uint16 from,
uint16 length, uint16 length,
uchar flags, uint16 flags,
uint16 lnkIndex, uint16 lnkIndex,
uint16 spoilerIndex) uint16 spoilerIndex)
: AbstractBlock(font, str, from, length, flags, lnkIndex, spoilerIndex) { : AbstractBlock(font, str, from, length, flags, lnkIndex, spoilerIndex) {
_flags |= ((TextBlockTNewline & 0x0F) << 8); _flags |= ((TextBlockTNewline & 0x0F) << 10);
} }
Qt::LayoutDirection NewlineBlock::nextDirection() const { Qt::LayoutDirection NewlineBlock::nextDirection() const {
@ -500,7 +500,7 @@ SkipBlock::SkipBlock(
uint16 spoilerIndex) uint16 spoilerIndex)
: AbstractBlock(font, str, from, 1, 0, lnkIndex, spoilerIndex) : AbstractBlock(font, str, from, 1, 0, lnkIndex, spoilerIndex)
, _height(h) { , _height(h) {
_flags |= ((TextBlockTSkip & 0x0F) << 8); _flags |= ((TextBlockTSkip & 0x0F) << 10);
_width = w; _width = w;
} }
@ -641,7 +641,7 @@ Block Block::Newline(
const QString &str, const QString &str,
uint16 from, uint16 from,
uint16 length, uint16 length,
uchar flags, uint16 flags,
uint16 lnkIndex, uint16 lnkIndex,
uint16 spoilerIndex) { uint16 spoilerIndex) {
return New<NewlineBlock>( return New<NewlineBlock>(
@ -660,7 +660,7 @@ Block Block::Text(
QFixed minResizeWidth, QFixed minResizeWidth,
uint16 from, uint16 from,
uint16 length, uint16 length,
uchar flags, uint16 flags,
uint16 lnkIndex, uint16 lnkIndex,
uint16 spoilerIndex) { uint16 spoilerIndex) {
return New<TextBlock>( return New<TextBlock>(
@ -679,7 +679,7 @@ Block Block::Emoji(
const QString &str, const QString &str,
uint16 from, uint16 from,
uint16 length, uint16 length,
uchar flags, uint16 flags,
uint16 lnkIndex, uint16 lnkIndex,
uint16 spoilerIndex, uint16 spoilerIndex,
EmojiPtr emoji) { EmojiPtr emoji) {

View file

@ -30,6 +30,7 @@ enum TextBlockFlags {
TextBlockFSemibold = 0x20, TextBlockFSemibold = 0x20,
TextBlockFCode = 0x40, TextBlockFCode = 0x40,
TextBlockFPre = 0x80, TextBlockFPre = 0x80,
TextBlockFPlainLink = 0x100,
}; };
class AbstractBlock { class AbstractBlock {
@ -58,13 +59,13 @@ protected:
const QString &str, const QString &str,
uint16 from, uint16 from,
uint16 length, uint16 length,
uchar flags, uint16 flags,
uint16 lnkIndex, uint16 lnkIndex,
uint16 spoilerIndex); uint16 spoilerIndex);
uint16 _from = 0; uint16 _from = 0;
uint32 _flags = 0; // 4 bits empty, 16 bits lnkIndex, 4 bits type, 8 bits flags uint32 _flags = 0; // 2 bits empty, 16 bits lnkIndex, 4 bits type, 10 bits flags
uint16 _spoilerIndex = 0; uint16 _spoilerIndex = 0;
@ -86,7 +87,7 @@ public:
const QString &str, const QString &str,
uint16 from, uint16 from,
uint16 length, uint16 length,
uchar flags, uint16 flags,
uint16 lnkIndex, uint16 lnkIndex,
uint16 spoilerIndex); uint16 spoilerIndex);
@ -126,7 +127,7 @@ public:
QFixed minResizeWidth, QFixed minResizeWidth,
uint16 from, uint16 from,
uint16 length, uint16 length,
uchar flags, uint16 flags,
uint16 lnkIndex, uint16 lnkIndex,
uint16 spoilerIndex); uint16 spoilerIndex);
@ -150,7 +151,7 @@ public:
const QString &str, const QString &str,
uint16 from, uint16 from,
uint16 length, uint16 length,
uchar flags, uint16 flags,
uint16 lnkIndex, uint16 lnkIndex,
uint16 spoilerIndex, uint16 spoilerIndex,
EmojiPtr emoji); EmojiPtr emoji);
@ -200,7 +201,7 @@ public:
const QString &str, const QString &str,
uint16 from, uint16 from,
uint16 length, uint16 length,
uchar flags, uint16 flags,
uint16 lnkIndex, uint16 lnkIndex,
uint16 spoilerIndex); uint16 spoilerIndex);
@ -210,7 +211,7 @@ public:
QFixed minResizeWidth, QFixed minResizeWidth,
uint16 from, uint16 from,
uint16 length, uint16 length,
uchar flags, uint16 flags,
uint16 lnkIndex, uint16 lnkIndex,
uint16 spoilerIndex); uint16 spoilerIndex);
@ -219,7 +220,7 @@ public:
const QString &str, const QString &str,
uint16 from, uint16 from,
uint16 length, uint16 length,
uchar flags, uint16 flags,
uint16 lnkIndex, uint16 lnkIndex,
uint16 spoilerIndex, uint16 spoilerIndex,
EmojiPtr emoji); EmojiPtr emoji);

View file

@ -25,6 +25,7 @@ enum class EntityType : uchar {
MentionName, MentionName,
BotCommand, BotCommand,
MediaTimestamp, MediaTimestamp,
PlainLink, // Senders in chat list, attachements in chat list, etc.
Bold, Bold,
Semibold, Semibold,
@ -241,6 +242,7 @@ enum {
TextParseHashtags = 0x010, TextParseHashtags = 0x010,
TextParseBotCommands = 0x020, TextParseBotCommands = 0x020,
TextParseMarkdown = 0x040, TextParseMarkdown = 0x040,
TextParsePlainLinks = 0x080,
}; };
struct TextWithTags { struct TextWithTags {

View file

@ -42,6 +42,10 @@ TextWithEntities Link(const QString &text, const QString &url) {
return WithSingleEntity(text, EntityType::CustomUrl, url); return WithSingleEntity(text, EntityType::CustomUrl, url);
} }
TextWithEntities PlainLink(const QString &text) {
return WithSingleEntity(text, EntityType::PlainLink);
}
TextWithEntities RichLangValue(const QString &text) { TextWithEntities RichLangValue(const QString &text) {
static const auto kStart = QRegularExpression("(\\*\\*|__)"); static const auto kStart = QRegularExpression("(\\*\\*|__)");

View file

@ -30,6 +30,7 @@ inline constexpr auto Upper = details::ToUpperType{};
[[nodiscard]] TextWithEntities Link( [[nodiscard]] TextWithEntities Link(
const QString &text, const QString &text,
const QString &url = "internal:action"); const QString &url = "internal:action");
[[nodiscard]] TextWithEntities PlainLink(const QString &text);
[[nodiscard]] TextWithEntities RichLangValue(const QString &text); [[nodiscard]] TextWithEntities RichLangValue(const QString &text);
[[nodiscard]] inline TextWithEntities WithEntities(const QString &text) { [[nodiscard]] inline TextWithEntities WithEntities(const QString &text) {
return { text }; return { text };