import SwiftUI struct NoteTextEditor: View { @Binding var text: String let remoteText: String? @State private var selection: TextSelection? = nil var body: some View { TextEditor(text: $text, selection: $selection) .onChange(of: remoteText) { oldValue, newValue in guard let newValue, newValue != text else { return } let previousRemote = oldValue ?? text // Where the remote edit begins let changeStart = commonPrefixUTF16Length(previousRemote, newValue) // How many UTF-16 units were inserted (positive) or removed (negative) let delta = newValue.utf16.count - previousRemote.utf16.count // Apply remote text first text = newValue // Get current cursor offset guard let selection, case .selection(let range) = selection.indices, let cursorPos = range.lowerBound.samePosition(in: text.utf16) else { return } let cursorUTF16 = text.utf16.distance( from: text.utf16.startIndex, to: cursorPos ) // Only shift if the change happened strictly before the cursor guard changeStart < cursorUTF16 else { return } let newCursorUTF16 = max(0, min(cursorUTF16 + delta, newValue.utf16.count)) let newUTF16 = newValue.utf16 let newUTF16Index = newUTF16.index(newUTF16.startIndex, offsetBy: newCursorUTF16) guard let newIndex = newUTF16Index.samePosition(in: newValue) else { return } self.selection = TextSelection(range: newIndex.. Int { var count = 0 let aUTF16 = a.utf16 let bUTF16 = b.utf16 let minLen = min(aUTF16.count, bUTF16.count) while count < minLen { let aIdx = aUTF16.index(aUTF16.startIndex, offsetBy: count) let bIdx = bUTF16.index(bUTF16.startIndex, offsetBy: count) guard aUTF16[aIdx] == bUTF16[bIdx] else { break } count += 1 } return count } }