@@ -120,6 +120,86 @@ - (void)setText:(NSString *)text
120120 });
121121}
122122
123+ // / setText(text) — undoable, cursor-safe, IME-safe
124+ // - (void)setText:(NSString *)text
125+ // {
126+ // UITextView *tv = _textView;
127+ // TypeRichTextInputView *owner = _owner;
128+ // if (!tv || !owner) return;
129+ //
130+ // dispatch_async(dispatch_get_main_queue(), ^{
131+ // // Never touch text while IME composing
132+ // if (tv.markedTextRange) return;
133+ //
134+ // NSString *newText = text ?: @"";
135+ // NSString *oldText = tv.text ?: @"";
136+ //
137+ // // No-op fast path
138+ // if ([oldText isEqualToString:newText]) {
139+ // return;
140+ // }
141+ //
142+ // owner.blockEmitting = YES;
143+ //
144+ // // Save selection (cursor)
145+ // NSRange oldSelection = tv.selectedRange;
146+ //
147+ // // Compute minimal diff range
148+ // NSRange replaceRange = DiffRange(oldText, newText);
149+ //
150+ // NSInteger insertStart = replaceRange.location;
151+ // NSInteger insertLength =
152+ // newText.length - (oldText.length - replaceRange.length);
153+ //
154+ // NSString *insertText =
155+ // insertLength > 0
156+ // ? [newText substringWithRange:
157+ // NSMakeRange(insertStart, insertLength)]
158+ // : @"";
159+ //
160+ // // Convert NSRange → UITextRange
161+ // UITextPosition *start =
162+ // [tv positionFromPosition:tv.beginningOfDocument
163+ // offset:replaceRange.location];
164+ // UITextPosition *end =
165+ // [tv positionFromPosition:tv.beginningOfDocument
166+ // offset:NSMaxRange(replaceRange)];
167+ //
168+ // if (!start || !end) {
169+ // owner.blockEmitting = NO;
170+ // return;
171+ // }
172+ //
173+ // UITextRange *uiRange =
174+ // [tv textRangeFromPosition:start toPosition:end];
175+ //
176+ // // THIS IS THE KEY LINE (undo-safe)
177+ // [tv replaceRange:uiRange withText:insertText];
178+ //
179+ // // ---- Restore selection correctly ----
180+ // NSInteger delta = insertText.length - replaceRange.length;
181+ //
182+ // NSInteger newLoc = oldSelection.location;
183+ // NSInteger newLen = oldSelection.length;
184+ //
185+ // if (oldSelection.location > replaceRange.location) {
186+ // newLoc = MAX(0, newLoc + delta);
187+ // }
188+ //
189+ // NSInteger max = tv.text.length;
190+ // newLoc = MIN(newLoc, max);
191+ // newLen = MIN(newLen, max - newLoc);
192+ //
193+ // tv.selectedRange = NSMakeRange(newLoc, newLen);
194+ //
195+ // owner.blockEmitting = NO;
196+ //
197+ // [owner updatePlaceholderVisibilityFromCommand];
198+ // [owner invalidateTextLayoutFromCommand];
199+ // [owner dispatchSelectionChangeIfNeeded];
200+ // });
201+ // }
202+
123203
124204// / setSelection(start, end)
125205- (void )setSelectionStart : (NSInteger )start end : (NSInteger )end {
@@ -155,7 +235,8 @@ - (void)insertTextAtStart:(NSInteger)start
155235 dispatch_async (dispatch_get_main_queue (), ^{
156236 if ([owner isTouchInProgress ]) return ;
157237 if (tv.markedTextRange ) return ;
158-
238+ // if ([owner isHandlingUserInput]) return;
239+
159240 owner.blockEmitting = YES ;
160241
161242 UITextPosition *s =
@@ -199,4 +280,31 @@ - (NSDictionary *)baseAttributesForTextView:(UITextView *)tv {
199280 NSForegroundColorAttributeName : tv.textColor ?: UIColor.blackColor
200281 };
201282}
283+
284+ static NSRange DiffRange (NSString *oldText, NSString *newText) {
285+ NSInteger oldLen = oldText.length ;
286+ NSInteger newLen = newText.length ;
287+
288+ NSInteger start = 0 ;
289+ while (start < oldLen &&
290+ start < newLen &&
291+ [oldText characterAtIndex: start] ==
292+ [newText characterAtIndex: start]) {
293+ start++;
294+ }
295+
296+ NSInteger endOld = oldLen;
297+ NSInteger endNew = newLen;
298+
299+ while (endOld > start &&
300+ endNew > start &&
301+ [oldText characterAtIndex: endOld - 1 ] ==
302+ [newText characterAtIndex: endNew - 1 ]) {
303+ endOld--;
304+ endNew--;
305+ }
306+
307+ return NSMakeRange (start, endOld - start);
308+ }
309+
202310@end
0 commit comments