diff --git a/ui/text/text.cpp b/ui/text/text.cpp index e24a385..a244a6a 100644 --- a/ui/text/text.cpp +++ b/ui/text/text.cpp @@ -156,112 +156,6 @@ bool IsBad(QChar ch) { } // namespace Text } // namespace Ui -QString textcmdSkipBlock(ushort w, ushort h) { - static QString cmd(5, TextCommand); - cmd[1] = QChar(TextCommandSkipBlock); - cmd[2] = QChar(w); - cmd[3] = QChar(h); - return cmd; -} - -QString textcmdStartLink(ushort lnkIndex) { - static QString cmd(4, TextCommand); - cmd[1] = QChar(TextCommandLinkIndex); - cmd[2] = QChar(lnkIndex); - return cmd; -} - -QString textcmdStartLink(const QString &url) { - if (url.size() >= 4096) return QString(); - - QString result; - result.reserve(url.size() + 4); - return result.append(TextCommand).append(QChar(TextCommandLinkText)).append(QChar(int(url.size()))).append(url).append(TextCommand); -} - -QString textcmdStopLink() { - return textcmdStartLink(0); -} - -QString textcmdLink(ushort lnkIndex, const QString &text) { - QString result; - result.reserve(4 + text.size() + 4); - return result.append(textcmdStartLink(lnkIndex)).append(text).append(textcmdStopLink()); -} - -QString textcmdLink(const QString &url, const QString &text) { - QString result; - result.reserve(4 + url.size() + text.size() + 4); - return result.append(textcmdStartLink(url)).append(text).append(textcmdStopLink()); -} - -QString textcmdStartSemibold() { - QString result; - result.reserve(3); - return result.append(TextCommand).append(QChar(TextCommandSemibold)).append(TextCommand); -} - -QString textcmdStopSemibold() { - QString result; - result.reserve(3); - return result.append(TextCommand).append(QChar(TextCommandNoSemibold)).append(TextCommand); -} - -QString textcmdStartSpoiler() { - QString result; - result.reserve(3); - return result.append(TextCommand).append(QChar(TextCommandSpoiler)).append(TextCommand); -} - -QString textcmdStopSpoiler() { - QString result; - result.reserve(3); - return result.append(TextCommand).append(QChar(TextCommandNoSpoiler)).append(TextCommand); -} - -const QChar *textSkipCommand(const QChar *from, const QChar *end, bool canLink) { - const QChar *result = from + 1; - if (*from != TextCommand || result >= end) return from; - - ushort cmd = result->unicode(); - ++result; - if (result >= end) return from; - - switch (cmd) { - case TextCommandBold: - case TextCommandNoBold: - case TextCommandSemibold: - case TextCommandNoSemibold: - case TextCommandItalic: - case TextCommandNoItalic: - case TextCommandUnderline: - case TextCommandNoUnderline: - case TextCommandSpoiler: - case TextCommandNoSpoiler: - break; - - case TextCommandLinkIndex: - if (result->unicode() > 0x7FFF) return from; - ++result; - break; - - case TextCommandLinkText: { - ushort len = result->unicode(); - if (len >= 4096 || !canLink) return from; - result += len + 1; - } break; - - case TextCommandSkipBlock: - result += 2; - break; - - case TextCommandLangTag: - result += 1; - break; - } - return (result < end && *result == TextCommand) ? (result + 1) : from; -} - const TextParseOptions _defaultOptions = { TextParseLinks | TextParseMultiline, // flags 0, // maxw @@ -328,15 +222,11 @@ private: void createBlock(int32 skipBack = 0); void createSkipBlock(int32 w, int32 h); void createNewlineBlock(); - bool checkCommand(); // Returns true if at least one entity was parsed in the current position. bool checkEntities(); - bool readSkipBlockCommand(); - bool readCommand(); void parseCurrentChar(); void parseEmojiFromCurrent(); - void checkForElidedSkipBlock(); void finalize(const TextParseOptions &options); void finishEntities(); @@ -528,17 +418,6 @@ void Parser::createNewlineBlock() { createBlock(); } -bool Parser::checkCommand() { - bool result = false; - for (QChar c = ((_ptr < _end) ? *_ptr : 0); c == TextCommand; c = ((_ptr < _end) ? *_ptr : 0)) { - if (!readCommand()) { - break; - } - result = true; - } - return result; -} - void Parser::finishEntities() { while (!_startedEntities.empty() && (_ptr >= _startedEntities.begin()->first || _ptr >= _end)) { @@ -691,149 +570,6 @@ void Parser::skipBadEntities() { } } -bool Parser::readSkipBlockCommand() { - const QChar *afterCmd = textSkipCommand(_ptr, _end, _links.size() < 0x7FFF); - if (afterCmd == _ptr) { - return false; - } - - ushort cmd = (++_ptr)->unicode(); - ++_ptr; - - switch (cmd) { - case TextCommandSkipBlock: - createSkipBlock(_ptr->unicode(), (_ptr + 1)->unicode()); - break; - } - - _ptr = afterCmd; - return true; -} - -bool Parser::readCommand() { - const QChar *afterCmd = textSkipCommand(_ptr, _end, _links.size() < 0x7FFF); - if (afterCmd == _ptr) { - return false; - } - - ushort cmd = (++_ptr)->unicode(); - ++_ptr; - - switch (cmd) { - case TextCommandBold: - if (!(_flags & TextBlockFBold)) { - createBlock(); - _flags |= TextBlockFBold; - } - break; - - case TextCommandNoBold: - if (_flags & TextBlockFBold) { - createBlock(); - _flags &= ~TextBlockFBold; - } - break; - - case TextCommandSemibold: - if (!(_flags & TextBlockFSemibold)) { - createBlock(); - _flags |= TextBlockFSemibold; - } - break; - - case TextCommandNoSemibold: - if (_flags & TextBlockFSemibold) { - createBlock(); - _flags &= ~TextBlockFSemibold; - } - break; - - case TextCommandItalic: - if (!(_flags & TextBlockFItalic)) { - createBlock(); - _flags |= TextBlockFItalic; - } - break; - - case TextCommandNoItalic: - if (_flags & TextBlockFItalic) { - createBlock(); - _flags &= ~TextBlockFItalic; - } - break; - - case TextCommandUnderline: - if (!(_flags & TextBlockFUnderline)) { - createBlock(); - _flags |= TextBlockFUnderline; - } - break; - - case TextCommandNoUnderline: - if (_flags & TextBlockFUnderline) { - createBlock(); - _flags &= ~TextBlockFUnderline; - } - break; - - case TextCommandStrikeOut: - if (!(_flags & TextBlockFStrikeOut)) { - createBlock(); - _flags |= TextBlockFStrikeOut; - } - break; - - case TextCommandNoStrikeOut: - if (_flags & TextBlockFStrikeOut) { - createBlock(); - _flags &= ~TextBlockFStrikeOut; - } - break; - - case TextCommandLinkIndex: - if (_ptr->unicode() != _lnkIndex) { - createBlock(); - _lnkIndex = _ptr->unicode(); - } - break; - - case TextCommandLinkText: { - createBlock(); - int32 len = _ptr->unicode(); - _links.push_back(EntityLinkData{ - .data = QString(++_ptr, len), - .type = EntityType::CustomUrl - }); - _lnkIndex = kStringLinkIndexShift + _links.size(); - } break; - - case TextCommandSpoiler: { - if (!_spoilerIndex) { - createBlock(); - _spoilers.push_back(EntityLinkData{ - .data = QString::number(_spoilers.size() + 1), - .type = EntityType::Spoiler, - }); - _spoilerIndex = _spoilers.size(); - } - } break; - - case TextCommandNoSpoiler: - if (_spoilerIndex == _spoilers.size()) { - createBlock(); - _spoilerIndex = 0; - } - break; - - case TextCommandSkipBlock: - createSkipBlock(_ptr->unicode(), (_ptr + 1)->unicode()); - break; - } - - _ptr = afterCmd; - return true; -} - void Parser::parseCurrentChar() { _ch = ((_ptr < _end) ? *_ptr : 0); _emojiLookback = 0; @@ -964,7 +700,7 @@ void Parser::parse(const TextParseOptions &options) { _t->_text.reserve(_end - _ptr); for (; _ptr <= _end; ++_ptr) { - while (checkEntities() || (_rich && checkCommand())) { + while (checkEntities()) { } parseCurrentChar(); parseEmojiFromCurrent(); @@ -974,7 +710,6 @@ void Parser::parse(const TextParseOptions &options) { } } createBlock(); - checkForElidedSkipBlock(); finalize(options); } @@ -983,25 +718,25 @@ void Parser::trimSourceRange() { _source.entities, _end - _start); - while (_ptr != _end && IsTrimmed(*_ptr, _rich) && _ptr != _start + firstMonospaceOffset) { + while (_ptr != _end && IsTrimmed(*_ptr) && _ptr != _start + firstMonospaceOffset) { ++_ptr; } - while (_ptr != _end && IsTrimmed(*(_end - 1), _rich)) { + while (_ptr != _end && IsTrimmed(*(_end - 1))) { --_end; } } -void Parser::checkForElidedSkipBlock() { - if (!_sumFinished || !_rich) { - return; - } - // We could've skipped the final skip block command. - for (; _ptr < _end; ++_ptr) { - if (*_ptr == TextCommand && readSkipBlockCommand()) { - break; - } - } -} +// void Parser::checkForElidedSkipBlock() { +// if (!_sumFinished || !_rich) { +// return; +// } +// // We could've skipped the final skip block command. +// for (; _ptr < _end; ++_ptr) { +// if (*_ptr == TextCommand && readSkipBlockCommand()) { +// break; +// } +// } +// } void Parser::finalize(const TextParseOptions &options) { _t->_links.resize(_maxLnkIndex); @@ -3795,8 +3530,7 @@ bool IsAlmostLinkEnd(QChar ch) { } bool IsLinkEnd(QChar ch) { - return (ch == TextCommand) - || IsBad(ch) + return IsBad(ch) || IsSpace(ch) || IsNewline(ch) || ch.isLowSurrogate() @@ -3808,9 +3542,9 @@ bool IsNewline(QChar ch) { || (ch == 156); } -bool IsSpace(QChar ch, bool rich) { +bool IsSpace(QChar ch) { return ch.isSpace() - || (ch < 32 && !(rich && ch == TextCommand)) + || (ch < 32) || (ch == QChar::ParagraphSeparator) || (ch == QChar::LineSeparator) || (ch == QChar::ObjectReplacementCharacter) @@ -3840,9 +3574,8 @@ bool IsReplacedBySpace(QChar ch) { || (ch >= 8232 && ch <= 8237); } -bool IsTrimmed(QChar ch, bool rich) { - return (!rich || ch != TextCommand) - && (IsSpace(ch) || IsBad(ch)); +bool IsTrimmed(QChar ch) { + return (IsSpace(ch) || IsBad(ch)); } } // namespace Text diff --git a/ui/text/text.h b/ui/text/text.h index 02612c6..e59438e 100644 --- a/ui/text/text.h +++ b/ui/text/text.h @@ -22,25 +22,6 @@ static const auto kQEllipsis = QStringLiteral("..."); } // namespace Ui static const QChar TextCommand(0x0010); -enum TextCommands { - TextCommandBold = 0x01, - TextCommandNoBold = 0x02, - TextCommandItalic = 0x03, - TextCommandNoItalic = 0x04, - TextCommandUnderline = 0x05, - TextCommandNoUnderline = 0x06, - TextCommandStrikeOut = 0x07, - TextCommandNoStrikeOut = 0x08, - TextCommandSemibold = 0x09, - TextCommandNoSemibold = 0x0A, - TextCommandLinkIndex = 0x0B, // 0 - NoLink - TextCommandLinkText = 0x0C, - TextCommandSkipBlock = 0x0D, - TextCommandSpoiler = 0x0E, - TextCommandNoSpoiler = 0x0F, - - TextCommandLangTag = 0x20, -}; struct TextParseOptions { int32 flags; @@ -253,10 +234,10 @@ private: [[nodiscard]] bool IsAlmostLinkEnd(QChar ch); [[nodiscard]] bool IsLinkEnd(QChar ch); [[nodiscard]] bool IsNewline(QChar ch); -[[nodiscard]] bool IsSpace(QChar ch, bool rich = false); +[[nodiscard]] bool IsSpace(QChar ch); [[nodiscard]] bool IsDiac(QChar ch); [[nodiscard]] bool IsReplacedBySpace(QChar ch); -[[nodiscard]] bool IsTrimmed(QChar ch, bool rich = false); +[[nodiscard]] bool IsTrimmed(QChar ch); } // namespace Text } // namespace Ui @@ -276,18 +257,3 @@ inline TextSelection shiftSelection(TextSelection selection, const Ui::Text::Str inline TextSelection unshiftSelection(TextSelection selection, const Ui::Text::String &byText) { return unshiftSelection(selection, byText.length()); } - -// textcmd -QString textcmdSkipBlock(ushort w, ushort h); -QString textcmdStartLink(ushort lnkIndex); -QString textcmdStartLink(const QString &url); -QString textcmdStopLink(); -QString textcmdLink(ushort lnkIndex, const QString &text); -QString textcmdLink(const QString &url, const QString &text); -QString textcmdStartSemibold(); -QString textcmdStopSemibold(); - -QString textcmdStartSpoiler(); -QString textcmdStopSpoiler(); - -const QChar *textSkipCommand(const QChar *from, const QChar *end, bool canLink = true); diff --git a/ui/text/text_entity.cpp b/ui/text/text_entity.cpp index 5c59c1a..36cb1e1 100644 --- a/ui/text/text_entity.cpp +++ b/ui/text/text_entity.cpp @@ -1293,35 +1293,17 @@ bool IsValidTopDomain(const QString &protocol) { return list.contains(base::crc32(protocol.constData(), protocol.size() * sizeof(QChar))); } -QString Clean(const QString &text, bool keepSpoilers) { - auto result = text; - for (auto s = text.unicode(), ch = s, e = text.unicode() + text.size(); ch != e; ++ch) { - if (keepSpoilers && (*ch == TextCommand)) { - if ((*(ch + 1) == TextCommandSpoiler) - || (*(ch - 1) == TextCommandSpoiler) - || (*(ch + 1) == TextCommandNoSpoiler) - || (*(ch - 1) == TextCommandNoSpoiler)) { - continue; - } - } - if (*ch == TextCommand) { - result[int(ch - s)] = QChar::Space; - } - } - return result; -} - QString EscapeForRichParsing(const QString &text) { QString result; result.reserve(text.size()); auto s = text.constData(), ch = s; for (const QChar *e = s + text.size(); ch != e; ++ch) { - if (*ch == TextCommand) { - if (ch > s) result.append(s, ch - s); - result.append(QChar::Space); - s = ch + 1; - continue; - } + // if (*ch == TextCommand) { + // if (ch > s) result.append(s, ch - s); + // result.append(QChar::Space); + // s = ch + 1; + // continue; + // } if (ch->unicode() == '\\' || ch->unicode() == '[') { if (ch > s) result.append(s, ch - s); result.append('\\'); @@ -1349,7 +1331,7 @@ QString SingleLine(const QString &text) { } for (auto ch = s; ch != e; ++ch) { - if (IsNewline(*ch) || *ch == TextCommand) { + if (IsNewline(*ch)/* || *ch == TextCommand*/) { result[int(ch - s)] = QChar::Space; } } @@ -1545,47 +1527,6 @@ bool CutPart(TextWithEntities &sending, TextWithEntities &left, int32 limit) { return true; } -bool textcmdStartsLink(const QChar *start, int32 len, int32 commandOffset) { - if (commandOffset + 2 < len) { - if (*(start + commandOffset + 1) == TextCommandLinkIndex) { - return (*(start + commandOffset + 2) != 0); - } - return (*(start + commandOffset + 1) != TextCommandLinkText); - } - return false; -} - -bool checkTagStartInCommand(const QChar *start, int32 len, int32 tagStart, int32 &commandOffset, bool &commandIsLink, bool &inLink) { - bool inCommand = false; - const QChar *commandEnd = start + commandOffset; - while (commandOffset < len && tagStart > commandOffset) { // skip commands, evaluating are we in link or not - commandEnd = textSkipCommand(start + commandOffset, start + len); - if (commandEnd > start + commandOffset) { - if (tagStart < (commandEnd - start)) { - inCommand = true; - break; - } - for (commandOffset = commandEnd - start; commandOffset < len; ++commandOffset) { - if (*(start + commandOffset) == TextCommand) { - inLink = commandIsLink; - commandIsLink = textcmdStartsLink(start, len, commandOffset); - break; - } - } - if (commandOffset >= len) { - inLink = commandIsLink; - commandIsLink = false; - } - } else { - break; - } - } - if (inCommand) { - commandOffset = commandEnd - start; - } - return inCommand; -} - TextWithEntities ParseEntities(const QString &text, int32 flags) { const auto rich = ((flags & TextParseRichText) != 0); auto result = TextWithEntities{ text, EntitiesInText() }; @@ -1605,20 +1546,10 @@ void ParseEntities(TextWithEntities &result, int32 flags, bool rich) { int existingEntityIndex = 0, existingEntitiesCount = result.entities.size(); int existingEntityEnd = 0; - int32 len = result.text.size(), commandOffset = rich ? 0 : len; - bool inLink = false, commandIsLink = false; + int32 len = result.text.size(); const auto start = result.text.constData(); const auto end = start + result.text.size(); for (int32 offset = 0, matchOffset = offset, mentionSkip = 0; offset < len;) { - if (commandOffset <= offset) { - for (commandOffset = offset; commandOffset < len; ++commandOffset) { - if (*(start + commandOffset) == TextCommand) { - inLink = commandIsLink; - commandIsLink = textcmdStartsLink(start, len, commandOffset); - break; - } - } - } auto mDomain = qthelp::RegExpDomain().match(result.text, matchOffset); auto mExplicitDomain = qthelp::RegExpDomainExplicit().match(result.text, matchOffset); auto mHashtag = withHashtags ? RegExpHashtag().match(result.text, matchOffset) : QRegularExpressionMatch(); @@ -1706,17 +1637,6 @@ void ParseEntities(TextWithEntities &result, int32 flags, bool rich) { offset = matchOffset = mentionEnd; continue; } - const auto inCommand = checkTagStartInCommand( - start, - len, - mentionStart, - commandOffset, - commandIsLink, - inLink); - if (inCommand || inLink) { - offset = matchOffset = commandOffset; - continue; - } lnkType = EntityType::Mention; lnkStart = mentionStart; @@ -1727,50 +1647,15 @@ void ParseEntities(TextWithEntities &result, int32 flags, bool rich) { offset = matchOffset = hashtagEnd; continue; } - const auto inCommand = checkTagStartInCommand( - start, - len, - hashtagStart, - commandOffset, - commandIsLink, - inLink); - if (inCommand || inLink) { - offset = matchOffset = commandOffset; - continue; - } lnkType = EntityType::Hashtag; lnkStart = hashtagStart; lnkLength = hashtagEnd - hashtagStart; } else if (botCommandStart < domainStart) { - const auto inCommand = checkTagStartInCommand( - start, - len, - botCommandStart, - commandOffset, - commandIsLink, - inLink); - if (inCommand || inLink) { - offset = matchOffset = commandOffset; - continue; - } - lnkType = EntityType::BotCommand; lnkStart = botCommandStart; lnkLength = botCommandEnd - botCommandStart; } else { - const auto inCommand = checkTagStartInCommand( - start, - len, - domainStart, - commandOffset, - commandIsLink, - inLink); - if (inCommand || inLink) { - offset = matchOffset = commandOffset; - continue; - } - auto protocol = mDomain.captured(1).toLower(); auto topDomain = mDomain.captured(3).toLower(); auto isProtocolValid = protocol.isEmpty() || IsValidProtocol(protocol); @@ -2332,36 +2217,6 @@ void SetClipboardText( } } -QString TextWithSpoilerCommands(const TextWithEntities &textWithEntities) { - auto text = textWithEntities.text; - auto offset = 0; - const auto start = textcmdStartSpoiler(); - const auto stop = textcmdStopSpoiler(); - for (const auto &e : textWithEntities.entities) { - if (e.type() == EntityType::Spoiler) { - text.insert(e.offset() + offset, start); - offset += start.size(); - text.insert(e.offset() + e.length() + offset, stop); - offset += stop.size(); - } - } - return text; -} - -QString CutTextWithCommands( - QString text, - int length, - const QString &start, - const QString &stop) { - text = text.mid(0, length); - const auto lastStart = text.lastIndexOf(start); - const auto lastStop = text.lastIndexOf(stop); - const auto additional = ((lastStart == -1) || (lastStart < lastStop)) - ? QString() - : stop; - return text + additional + Ui::kQEllipsis; -} - } // namespace TextUtilities EntityInText::EntityInText( diff --git a/ui/text/text_entity.h b/ui/text/text_entity.h index cbc1168..dc68218 100644 --- a/ui/text/text_entity.h +++ b/ui/text/text_entity.h @@ -297,7 +297,6 @@ QString MarkdownSpoilerGoodBefore(); QString MarkdownSpoilerBadAfter(); // Text preprocess. -QString Clean(const QString &text, bool keepSpoilers = false); QString EscapeForRichParsing(const QString &text); QString SingleLine(const QString &text); TextWithEntities SingleLine(const TextWithEntities &text); @@ -383,12 +382,4 @@ void SetClipboardText( const TextForMimeData &text, QClipboard::Mode mode = QClipboard::Clipboard); -[[nodiscard]] QString TextWithSpoilerCommands( - const TextWithEntities &textWithEntities); -[[nodiscard]] QString CutTextWithCommands( - QString text, - int length, - const QString &start, - const QString &stop); - } // namespace TextUtilities