Use double underscores for italic chat markup

This commit is contained in:
evgeny committed 2026-11-02 22:42:13 +01:00
1 parent b17c6fff96
commit 66b8da36b8
2 files changed
+8 -7

No files matched your search

+7 -6
View File
@@ -24,7 +24,7 @@ bool MessageText::isCode(int position) const {
namespace {
struct Marker {
int position, length, kind; // Позиция в строке после escapes; kind: 0=**, 1=*, 2=~~.
int position, length, kind; // Позиция в строке после escapes; kind: 0=**, 1=__, 2=~~.
bool open, close; // Открытие/закрытие допустимо только около непустого текста.
int nextClose = -1; // Следующий закрывающий маркер того же вида; поиск за O(n).
};
@@ -39,19 +39,19 @@ void appendInline(MessageText& result, const QString& source) {
while (linkIndex < links.size() && links[linkIndex].start + links[linkIndex].length <= i) ++linkIndex;
const bool inLink = linkIndex < links.size() && links[linkIndex].start <= i;
const QChar ch = source[i];
if (!inLink && ch == '\\' && i + 1 < source.size() && QStringLiteral("*~`\\").contains(source[i + 1])) {
if (!inLink && ch == '\\' && i + 1 < source.size() && QStringLiteral("*_~`\\").contains(source[i + 1])) {
line += source[i + 1]; i += 2; result.changed = true; continue;
}
int count = 1;
if (ch == '*' || ch == '~') {
if (ch == '*' || ch == '_' || ch == '~') {
while (i + count < source.size() && source[i + count] == ch) ++count;
if ((ch == '*' && count <= 2) || (ch == '~' && count == 2)) {
if (count == 2) {
const bool open = !inLink && i + count < source.size() && !source[i + count].isSpace()
&& (i == 0 || !source[i - 1].isLetterOrNumber());
const bool close = i > 0 && !source[i - 1].isSpace()
&& (!inLink || i + count == links[linkIndex].start + links[linkIndex].length)
&& (i + count == source.size() || !source[i + count].isLetterOrNumber());
markers.append({int(line.size()), count, ch == '~' ? 2 : count == 2 ? 0 : 1, open, close});
markers.append({int(line.size()), count, ch == '*' ? 0 : ch == '_' ? 1 : 2, open, close});
}
}
line += source.mid(i, count); i += count;
@@ -152,7 +152,8 @@ QSharedPointer<const MessageText> formattedMessageText(const QModelIndex& index)
const QString type = index.data(MsgContentTypeRole).toString();
if ((!type.isEmpty() && type != "text/plain") || !index.data(MsgInviteLinkRole).toString().isEmpty()) return {};
const QString source = index.data(MsgTextRole).toString();
if (!source.contains('*') && !source.contains("~~") && !source.contains('`') && !source.contains('\\')) return {};
if (!source.contains("**") && !source.contains("__") && !source.contains("~~") && !source.contains('`') && !source.contains('\\'))
return {};
// Ограничение учитывает текст ключа, видимый текст и диапазоны; shared pointer жив до конца paint/hit-test.
static QCache<QString, QSharedPointer<const MessageText>> cache(8 * 1024 * 1024);
if (const auto* cached = cache.object(source)) return *cached;
+1 -1
View File
@@ -1,4 +1,4 @@
/* Разметка текста сообщений: **жирный**, *курсив*, ~~зачёркнутый~~ и отдельные строки ```[язык]/```.
/* Разметка текста сообщений: **жирный**, __курсив__, ~~зачёркнутый~~ и отдельные строки ```[язык]/```.
* Исходник модели не меняется. GUI-поток получает кешированный видимый текст, ссылки и цвета синтаксиса.
* Один QTextLayout используется для размеров, рисования и выделения; clipboard берёт MessageText::text. */
#pragma once