From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: alina sireneva <alina@tei.su>
Date: Fri, 29 May 2026 01:04:39 +0400
Subject: fix formatting over overlapping different entities spilling the last one

---
 .../ui/Components/EditTextCaption.java        | 71 ++++++++++++++++++-
 1 file changed, 70 insertions(+), 1 deletion(-)

diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/EditTextCaption.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/EditTextCaption.java
index 0000000..0000000 100644
--- a/TMessagesProj/src/main/java/org/telegram/ui/Components/EditTextCaption.java
+++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/EditTextCaption.java
@@ -706,7 +706,11 @@ public class EditTextCaption extends EditTextBoldCursor implements FloatingToolb
             start = getSelectionStart();
             end = getSelectionEnd();
         }
-        MediaDataController.addStyleToText(span, start, end, getText(), allowTextEntitiesIntersection);
+        if (span != null) {
+            inu_applyTextStyleToSelection(span, start, end);
+        } else {
+            MediaDataController.addStyleToText(null, start, end, getText(), allowTextEntitiesIntersection);
+        }
 
         if (span == null) {
             Editable editable = getText();
@@ -731,6 +735,71 @@ public class EditTextCaption extends EditTextBoldCursor implements FloatingToolb
         }
     }
 
+    // stock MediaDataController.addStyleToText carves the unstyled remainder with a single (start,end) pair,
+    // so with 2+ overlapping spans in the selection it re-splits later spans against the wrong bounds and
+    // smears them across the gap (e.g. mono leaking over the whole selection). split each span independently.
+    private void inu_applyTextStyleToSelection(TextStyleSpan span, int start, int end) {
+        Editable editable = getText();
+        if (editable == null) return;
+        if (start > end) { int t = start; start = end; end = t; }
+        if (start < 0) start = 0;
+        if (end > editable.length()) end = editable.length();
+        if (start >= end) return;
+
+        TextStyleSpan.TextStyleRun newRun = span.getTextStyleRun();
+        boolean[] covered = new boolean[end - start];
+
+        for (CharacterStyle old : editable.getSpans(start, end, CharacterStyle.class)) {
+            TextStyleSpan.TextStyleRun run;
+            if (old instanceof TextStyleSpan) {
+                run = ((TextStyleSpan) old).getTextStyleRun();
+            } else if (old instanceof URLSpanReplacement) {
+                run = ((URLSpanReplacement) old).getTextStyleRun();
+                if (run == null) run = new TextStyleSpan.TextStyleRun();
+            } else {
+                continue;
+            }
+            int ss = editable.getSpanStart(old);
+            int se = editable.getSpanEnd(old);
+            int oStart = Math.max(start, ss);
+            int oEnd = Math.min(end, se);
+            editable.removeSpan(old);
+            if (ss < oStart) {
+                editable.setSpan(inu_cloneStyleSpan(old, run, null), ss, oStart, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+            }
+            if (oStart < oEnd) {
+                editable.setSpan(inu_cloneStyleSpan(old, run, newRun), oStart, oEnd, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+                for (int i = oStart - start; i < oEnd - start; i++) covered[i] = true;
+            }
+            if (oEnd < se) {
+                editable.setSpan(inu_cloneStyleSpan(old, run, null), oEnd, se, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+            }
+        }
+
+        int i = 0;
+        while (i < covered.length) {
+            if (covered[i]) { i++; continue; }
+            int gap = i;
+            while (i < covered.length && !covered[i]) i++;
+            editable.setSpan(new TextStyleSpan(new TextStyleSpan.TextStyleRun(newRun)), start + gap, start + i, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+        }
+    }
+
+    private CharacterStyle inu_cloneStyleSpan(CharacterStyle base, TextStyleSpan.TextStyleRun baseRun, TextStyleSpan.TextStyleRun mergeRun) {
+        TextStyleSpan.TextStyleRun run = new TextStyleSpan.TextStyleRun(baseRun);
+        if (mergeRun != null) {
+            if (allowTextEntitiesIntersection) {
+                run.merge(mergeRun);
+            } else {
+                run.replace(mergeRun);
+            }
+        }
+        if (base instanceof URLSpanReplacement) {
+            return new URLSpanReplacement(((URLSpanReplacement) base).getURL(), run);
+        }
+        return new TextStyleSpan(run);
+    }
+
     @Override
     public void onWindowFocusChanged(boolean hasWindowFocus) {
         if (Build.VERSION.SDK_INT < 23 && !hasWindowFocus && copyPasteShowed) {
