diff --git a/telethon/extensions/html.py b/telethon/extensions/html.py
index 201312ac..b9661316 100644
--- a/telethon/extensions/html.py
+++ b/telethon/extensions/html.py
@@ -175,7 +175,7 @@ def unparse(text: str, entities: Iterable[TypeMessageEntity]) -> str:
if callable(delimiter):
delimiter = delimiter(entity, text[s:e])
insert_at.append((s, i, delimiter[0]))
- insert_at.append((e, len(entities) - i, delimiter[1]))
+ insert_at.append((e, -i, delimiter[1]))
insert_at.sort(key=lambda t: (t[0], t[1]))
next_escape_bound = len(text)
diff --git a/telethon/extensions/markdown.py b/telethon/extensions/markdown.py
index 78f28385..82e90345 100644
--- a/telethon/extensions/markdown.py
+++ b/telethon/extensions/markdown.py
@@ -170,7 +170,7 @@ def unparse(text, entities, delimiters=None, url_fmt=None):
delimiter = delimiters.get(type(entity), None)
if delimiter:
insert_at.append((s, i, delimiter))
- insert_at.append((e, len(entities) - i, delimiter))
+ insert_at.append((e, -i, delimiter))
else:
url = None
if isinstance(entity, MessageEntityTextUrl):
@@ -179,7 +179,7 @@ def unparse(text, entities, delimiters=None, url_fmt=None):
url = 'tg://user?id={}'.format(entity.user_id)
if url:
insert_at.append((s, i, '['))
- insert_at.append((e, len(entities) - i, ']({})'.format(url)))
+ insert_at.append((e, -i, ']({})'.format(url)))
insert_at.sort(key=lambda t: (t[0], t[1]))
while insert_at:
diff --git a/tests/telethon/extensions/test_html.py b/tests/telethon/extensions/test_html.py
index 59d96e0d..302913cc 100644
--- a/tests/telethon/extensions/test_html.py
+++ b/tests/telethon/extensions/test_html.py
@@ -53,6 +53,22 @@ def test_entities_together():
assert text == original
+def test_nested_entities():
+ """
+ Test that an entity nested inside another one behaves well.
+ """
+ original = 'Example'
+ original_entities = [MessageEntityTextUrl(0, 7, url='https://example.com'), MessageEntityBold(0, 7)]
+ stripped = 'Example'
+
+ text, entities = html.parse(original)
+ assert text == stripped
+ assert entities == original_entities
+
+ text = html.unparse(text, entities)
+ assert text == original
+
+
def test_offset_at_emoji():
"""
Tests that an entity starting at a emoji preserves the emoji.
diff --git a/tests/telethon/extensions/test_markdown.py b/tests/telethon/extensions/test_markdown.py
index bd78e4d8..2eb94b06 100644
--- a/tests/telethon/extensions/test_markdown.py
+++ b/tests/telethon/extensions/test_markdown.py
@@ -53,6 +53,21 @@ def test_entities_together():
assert text == original
+def test_nested_entities():
+ """
+ Test that an entity nested inside another one behaves well.
+ """
+ original = '**[Example](https://example.com)**'
+ stripped = 'Example'
+
+ text, entities = markdown.parse(original)
+ assert text == stripped
+ assert entities == [MessageEntityBold(0, 7), MessageEntityTextUrl(0, 7, url='https://example.com')]
+
+ text = markdown.unparse(text, entities)
+ assert text == original
+
+
def test_offset_at_emoji():
"""
Tests that an entity starting at a emoji preserves the emoji.