lang_text_entity.cpp 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  1. /*
  2. This file is part of Telegram Desktop,
  3. the official desktop application for the Telegram messaging service.
  4. For license and copyright information please follow this link:
  5. https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
  6. */
  7. #include "lang/lang_text_entity.h"
  8. #include "lang/lang_tag.h"
  9. namespace Lang {
  10. TextWithEntities ReplaceTag<TextWithEntities>::Call(TextWithEntities &&original, ushort tag, const TextWithEntities &replacement) {
  11. auto replacementPosition = FindTagReplacementPosition(original.text, tag);
  12. if (replacementPosition < 0) {
  13. return std::move(original);
  14. }
  15. return Replace(std::move(original), replacement, replacementPosition);
  16. }
  17. TextWithEntities ReplaceTag<TextWithEntities>::Replace(TextWithEntities &&original, const TextWithEntities &replacement, int start) {
  18. auto result = TextWithEntities();
  19. result.text = ReplaceTag<QString>::Replace(std::move(original.text), replacement.text, start);
  20. auto originalEntitiesCount = original.entities.size();
  21. auto replacementEntitiesCount = replacement.entities.size();
  22. if (originalEntitiesCount != 0 || replacementEntitiesCount != 0) {
  23. result.entities.reserve(originalEntitiesCount + replacementEntitiesCount);
  24. auto replacementEnd = start + int(replacement.text.size());
  25. auto replacementEntity = replacement.entities.cbegin();
  26. auto addReplacementEntitiesUntil = [&](int untilPosition) {
  27. while (replacementEntity != replacement.entities.cend()) {
  28. auto newOffset = start + replacementEntity->offset();
  29. if (newOffset >= untilPosition) {
  30. return;
  31. }
  32. auto newEnd = newOffset + replacementEntity->length();
  33. newOffset = std::clamp(newOffset, start, replacementEnd);
  34. newEnd = std::clamp(newEnd, start, replacementEnd);
  35. if (auto newLength = newEnd - newOffset) {
  36. result.entities.push_back({ replacementEntity->type(), newOffset, newLength, replacementEntity->data() });
  37. }
  38. ++replacementEntity;
  39. }
  40. };
  41. for (const auto &entity : std::as_const(original.entities)) {
  42. // Transform the entity by the replacement.
  43. auto offset = entity.offset();
  44. auto end = offset + entity.length();
  45. if (offset > start) {
  46. offset = offset + replacement.text.size() - kTagReplacementSize;
  47. }
  48. if (end > start) {
  49. end = end + replacement.text.size() - kTagReplacementSize;
  50. }
  51. offset = std::clamp(offset, 0, int(result.text.size()));
  52. end = std::clamp(end, 0, int(result.text.size()));
  53. // Add all replacement entities that start before the current original entity.
  54. addReplacementEntitiesUntil(offset);
  55. // Add a modified original entity.
  56. if (auto length = end - offset) {
  57. result.entities.push_back({ entity.type(), offset, length, entity.data() });
  58. }
  59. }
  60. // Add the remaining replacement entities.
  61. addReplacementEntitiesUntil(result.text.size());
  62. }
  63. return result;
  64. }
  65. } // namespace Lang