forked from eatvio/eatvio_app
68 lines
3.1 KiB
Dart
68 lines
3.1 KiB
Dart
/// Утилиты для обработки markdown текста
|
|
class MarkdownUtils {
|
|
/// Обрабатывает markdown текст:
|
|
/// - Исправляет неправильный синтаксис markdown ссылок
|
|
/// - Автоматически преобразует URL в markdown ссылки
|
|
/// - Преобразует **текст** в <b>текст</b> для надежного отображения жирного текста
|
|
static String processMarkdown(String text) {
|
|
// Сначала исправляем неправильный синтаксис markdown ссылок
|
|
// Например: [http://example.com](url) -> [http://example.com](http://example.com)
|
|
final wrongLinkRegex = RegExp(r'\[(https?://[^\]]+|www\.[^\]]+)\]\(([^\)]+)\)');
|
|
text = text.replaceAllMapped(wrongLinkRegex, (match) {
|
|
final urlInText = match.group(1)!;
|
|
if (!urlInText.startsWith('http://') && !urlInText.startsWith('https://') && !urlInText.startsWith('www.')) {
|
|
return match.group(0)!;
|
|
}
|
|
final fullUrl = urlInText.startsWith('www.') ? 'https://$urlInText' : urlInText;
|
|
return '[$urlInText]($fullUrl)';
|
|
});
|
|
|
|
// Находим все существующие markdown ссылки и их позиции
|
|
final linkRegex = RegExp(r'\[([^\]]+)\]\(([^\)]+)\)');
|
|
final existingLinks = <_LinkRange>[];
|
|
for (final linkMatch in linkRegex.allMatches(text)) {
|
|
existingLinks.add(_LinkRange(linkMatch.start, linkMatch.end));
|
|
}
|
|
|
|
// Регулярное выражение для поиска URL (http://, https://, www.)
|
|
final urlRegex = RegExp(r'(https?://[^\s\)]+|www\.[^\s\)]+)', caseSensitive: false);
|
|
|
|
// Заменяем URL на markdown ссылки, если они еще не являются ссылками
|
|
String result = text;
|
|
int offset = 0;
|
|
for (final urlMatch in urlRegex.allMatches(text)) {
|
|
// Проверяем, не находится ли URL внутри существующей markdown ссылки
|
|
bool isInsideLink = existingLinks.any((link) =>
|
|
urlMatch.start >= link.start && urlMatch.end <= link.end);
|
|
if (!isInsideLink) {
|
|
final url = urlMatch.group(0)!;
|
|
final fullUrl = url.startsWith('www.') ? 'https://$url' : url;
|
|
final replacement = '[$url]($fullUrl)';
|
|
result = result.replaceRange(
|
|
urlMatch.start + offset,
|
|
urlMatch.end + offset,
|
|
replacement,
|
|
);
|
|
offset += replacement.length - url.length;
|
|
}
|
|
}
|
|
|
|
// Гарантируем, что жирный текст будет распознан
|
|
// Заменяем **текст** на <b>текст</b> вручную для надежности
|
|
final boldRegex = RegExp(r'\*\*([^*]+)\*\*');
|
|
result = result.replaceAllMapped(boldRegex, (match) {
|
|
return '<b>${match.group(1)}</b>';
|
|
});
|
|
|
|
return result;
|
|
}
|
|
}
|
|
|
|
/// Вспомогательный класс для хранения диапазона позиций ссылки
|
|
class _LinkRange {
|
|
final int start;
|
|
final int end;
|
|
|
|
_LinkRange(this.start, this.end);
|
|
}
|