mirror of https://github.com/procxx/kepka.git
Apply markdown bold/italic when editing a message.
This commit is contained in:
parent
148c04fb41
commit
921c27c9b1
|
@ -1959,21 +1959,39 @@ QString ApplyEntities(const TextWithEntities &text) {
|
||||||
if (text.entities.isEmpty()) return text.text;
|
if (text.entities.isEmpty()) return text.text;
|
||||||
|
|
||||||
QMultiMap<int32, QString> closingTags;
|
QMultiMap<int32, QString> closingTags;
|
||||||
QString code(qsl("`")), pre(qsl("```"));
|
QMap<EntityInTextType, QString> tags;
|
||||||
|
tags.insert(EntityInTextCode, qsl("`"));
|
||||||
|
tags.insert(EntityInTextPre, qsl("```"));
|
||||||
|
tags.insert(EntityInTextBold, qsl("**"));
|
||||||
|
tags.insert(EntityInTextItalic, qsl("__"));
|
||||||
|
constexpr auto kLargestOpenCloseLength = 6;
|
||||||
|
|
||||||
QString result;
|
QString result;
|
||||||
int32 size = text.text.size();
|
int32 size = text.text.size();
|
||||||
const QChar *b = text.text.constData(), *already = b, *e = b + size;
|
const QChar *b = text.text.constData(), *already = b, *e = b + size;
|
||||||
auto entity = text.entities.cbegin(), end = text.entities.cend();
|
auto entity = text.entities.cbegin(), end = text.entities.cend();
|
||||||
while (entity != end && ((entity->type() != EntityInTextCode && entity->type() != EntityInTextPre) || entity->length() <= 0 || entity->offset() >= size)) {
|
auto skipTillRelevantAndGetTag = [&entity, &end, size, &tags] {
|
||||||
++entity;
|
while (entity != end) {
|
||||||
}
|
if (entity->length() <= 0 || entity->offset() >= size) {
|
||||||
|
++entity;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
auto it = tags.constFind(entity->type());
|
||||||
|
if (it == tags.cend()) {
|
||||||
|
++entity;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
return it.value();
|
||||||
|
}
|
||||||
|
return QString();
|
||||||
|
};
|
||||||
|
|
||||||
|
auto tag = skipTillRelevantAndGetTag();
|
||||||
while (entity != end || !closingTags.isEmpty()) {
|
while (entity != end || !closingTags.isEmpty()) {
|
||||||
int32 nextOpenEntity = (entity == end) ? (size + 1) : entity->offset();
|
auto nextOpenEntity = (entity == end) ? (size + 1) : entity->offset();
|
||||||
int32 nextCloseEntity = closingTags.isEmpty() ? (size + 1) : closingTags.cbegin().key();
|
auto nextCloseEntity = closingTags.isEmpty() ? (size + 1) : closingTags.cbegin().key();
|
||||||
if (nextOpenEntity <= nextCloseEntity) {
|
if (nextOpenEntity <= nextCloseEntity) {
|
||||||
QString tag = (entity->type() == EntityInTextCode) ? code : pre;
|
if (result.isEmpty()) result.reserve(text.text.size() + text.entities.size() * kLargestOpenCloseLength);
|
||||||
if (result.isEmpty()) result.reserve(text.text.size() + text.entities.size() * pre.size() * 2);
|
|
||||||
|
|
||||||
const QChar *offset = b + nextOpenEntity;
|
const QChar *offset = b + nextOpenEntity;
|
||||||
if (offset > already) {
|
if (offset > already) {
|
||||||
|
@ -1984,9 +2002,7 @@ QString ApplyEntities(const TextWithEntities &text) {
|
||||||
closingTags.insert(qMin(entity->offset() + entity->length(), size), tag);
|
closingTags.insert(qMin(entity->offset() + entity->length(), size), tag);
|
||||||
|
|
||||||
++entity;
|
++entity;
|
||||||
while (entity != end && ((entity->type() != EntityInTextCode && entity->type() != EntityInTextPre) || entity->length() <= 0 || entity->offset() >= size)) {
|
tag = skipTillRelevantAndGetTag();
|
||||||
++entity;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
const QChar *offset = b + nextCloseEntity;
|
const QChar *offset = b + nextCloseEntity;
|
||||||
if (offset > already) {
|
if (offset > already) {
|
||||||
|
@ -2007,33 +2023,40 @@ QString ApplyEntities(const TextWithEntities &text) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void moveStringPart(QChar *start, int32 &to, int32 &from, int32 count, EntitiesInText *inOutEntities) {
|
void MoveStringPart(TextWithEntities &result, int to, int from, int count) {
|
||||||
if (count > 0) {
|
if (!count) return;
|
||||||
if (to < from) {
|
if (to != from) {
|
||||||
memmove(start + to, start + from, count * sizeof(QChar));
|
auto start = result.text.data();
|
||||||
for (auto &entity : *inOutEntities) {
|
memmove(start + to, start + from, count * sizeof(QChar));
|
||||||
if (entity.offset() >= from + count) break;
|
|
||||||
if (entity.offset() + entity.length() < from) continue;
|
for (auto &entity : result.entities) {
|
||||||
if (entity.offset() >= from) {
|
if (entity.offset() >= from + count) break;
|
||||||
entity.extendToLeft(from - to);
|
if (entity.offset() + entity.length() <= from) continue;
|
||||||
}
|
if (entity.offset() >= from) {
|
||||||
if (entity.offset() + entity.length() < from + count) {
|
entity.extendToLeft(from - to);
|
||||||
entity.shrinkFromRight(from - to);
|
}
|
||||||
}
|
if (entity.offset() + entity.length() <= from + count) {
|
||||||
|
entity.shrinkFromRight(from - to);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
to += count;
|
|
||||||
from += count;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void replaceStringWithEntities(const QLatin1String &from, QChar to, TextWithEntities &result, bool checkSpace = false) {
|
void MovePartAndGoForward(TextWithEntities &result, int &to, int &from, int count) {
|
||||||
|
if (!count) return;
|
||||||
|
MoveStringPart(result, to, from, count);
|
||||||
|
to += count;
|
||||||
|
from += count;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReplaceStringWithChar(const QLatin1String &from, QChar to, TextWithEntities &result, bool checkSpace = false) {
|
||||||
|
Expects(from.size() > 1);
|
||||||
auto len = from.size(), s = result.text.size(), offset = 0, length = 0;
|
auto len = from.size(), s = result.text.size(), offset = 0, length = 0;
|
||||||
auto i = result.entities.begin(), e = result.entities.end();
|
auto i = result.entities.begin(), e = result.entities.end();
|
||||||
for (QChar *start = result.text.data(); offset < s;) {
|
for (auto start = result.text.data(); offset < s;) {
|
||||||
int32 nextOffset = result.text.indexOf(from, offset);
|
auto nextOffset = result.text.indexOf(from, offset);
|
||||||
if (nextOffset < 0) {
|
if (nextOffset < 0) {
|
||||||
moveStringPart(start, length, offset, s - offset, &result.entities);
|
MovePartAndGoForward(result, length, offset, s - offset);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2041,12 +2064,12 @@ void replaceStringWithEntities(const QLatin1String &from, QChar to, TextWithEnti
|
||||||
bool spaceBefore = (nextOffset > 0) && (start + nextOffset - 1)->isSpace();
|
bool spaceBefore = (nextOffset > 0) && (start + nextOffset - 1)->isSpace();
|
||||||
bool spaceAfter = (nextOffset + len < s) && (start + nextOffset + len)->isSpace();
|
bool spaceAfter = (nextOffset + len < s) && (start + nextOffset + len)->isSpace();
|
||||||
if (!spaceBefore && !spaceAfter) {
|
if (!spaceBefore && !spaceAfter) {
|
||||||
moveStringPart(start, length, offset, nextOffset - offset + len + 1, &result.entities);
|
MovePartAndGoForward(result, length, offset, nextOffset - offset + len + 1);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool skip = false;
|
auto skip = false;
|
||||||
for (; i != e; ++i) { // find and check next finishing entity
|
for (; i != e; ++i) { // find and check next finishing entity
|
||||||
if (i->offset() + i->length() > nextOffset) {
|
if (i->offset() + i->length() > nextOffset) {
|
||||||
skip = (i->offset() < nextOffset + len);
|
skip = (i->offset() < nextOffset + len);
|
||||||
|
@ -2054,11 +2077,11 @@ void replaceStringWithEntities(const QLatin1String &from, QChar to, TextWithEnti
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (skip) {
|
if (skip) {
|
||||||
moveStringPart(start, length, offset, nextOffset - offset + len, &result.entities);
|
MovePartAndGoForward(result, length, offset, nextOffset - offset + len);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
moveStringPart(start, length, offset, nextOffset - offset, &result.entities);
|
MovePartAndGoForward(result, length, offset, nextOffset - offset);
|
||||||
|
|
||||||
*(start + length) = to;
|
*(start + length) = to;
|
||||||
++length;
|
++length;
|
||||||
|
@ -2074,9 +2097,9 @@ void PrepareForSending(TextWithEntities &result, int32 flags) {
|
||||||
ParseEntities(result, flags);
|
ParseEntities(result, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
replaceStringWithEntities(qstr("--"), QChar(8212), result, true);
|
ReplaceStringWithChar(qstr("--"), QChar(8212), result, true);
|
||||||
replaceStringWithEntities(qstr("<<"), QChar(171), result);
|
ReplaceStringWithChar(qstr("<<"), QChar(171), result);
|
||||||
replaceStringWithEntities(qstr(">>"), QChar(187), result);
|
ReplaceStringWithChar(qstr(">>"), QChar(187), result);
|
||||||
|
|
||||||
if (cReplaceEmojis()) {
|
if (cReplaceEmojis()) {
|
||||||
Ui::Emoji::ReplaceInText(result);
|
Ui::Emoji::ReplaceInText(result);
|
||||||
|
@ -2087,18 +2110,39 @@ void PrepareForSending(TextWithEntities &result, int32 flags) {
|
||||||
|
|
||||||
// Replace bad symbols with space and remove '\r'.
|
// Replace bad symbols with space and remove '\r'.
|
||||||
void ApplyServerCleaning(TextWithEntities &result) {
|
void ApplyServerCleaning(TextWithEntities &result) {
|
||||||
result.text = result.text.replace('\t', qstr(" ")); // TODO WTF? modify entities!
|
auto len = result.text.size();
|
||||||
int32 len = result.text.size(), to = 0, from = 0;
|
|
||||||
QChar *start = result.text.data();
|
// Replace tabs with two spaces.
|
||||||
for (QChar *ch = start, *end = start + len; ch < end; ++ch) {
|
if (auto tabs = std::count(result.text.cbegin(), result.text.cend(), '\t')) {
|
||||||
|
auto replacement = qsl(" ");
|
||||||
|
auto replacementLength = replacement.size();
|
||||||
|
auto shift = (replacementLength - 1);
|
||||||
|
result.text.resize(len + shift * tabs);
|
||||||
|
for (auto i = len, movedTill = len, to = result.text.size(); i > 0; --i) {
|
||||||
|
if (result.text[i - 1] == '\t') {
|
||||||
|
auto toMove = movedTill - i;
|
||||||
|
to -= toMove;
|
||||||
|
MoveStringPart(result, to, i, toMove);
|
||||||
|
to -= replacementLength;
|
||||||
|
memcpy(result.text.data() + to, replacement.constData(), replacementLength * sizeof(QChar));
|
||||||
|
movedTill = i - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
len = result.text.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto to = 0;
|
||||||
|
auto from = 0;
|
||||||
|
auto start = result.text.data();
|
||||||
|
for (auto ch = start, end = start + len; ch < end; ++ch) {
|
||||||
if (ch->unicode() == '\r') {
|
if (ch->unicode() == '\r') {
|
||||||
moveStringPart(start, to, from, (ch - start) - from, &result.entities);
|
MovePartAndGoForward(result, to, from, (ch - start) - from);
|
||||||
++from;
|
++from;
|
||||||
} else if (chReplacedBySpace(*ch)) {
|
} else if (chReplacedBySpace(*ch)) {
|
||||||
*ch = ' ';
|
*ch = ' ';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
moveStringPart(start, to, from, len - from, &result.entities);
|
MovePartAndGoForward(result, to, from, len - from);
|
||||||
if (to < len) result.text.resize(to);
|
if (to < len) result.text.resize(to);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue