Bugfixes, simplifications
This commit is contained in:
@@ -2,60 +2,15 @@ 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..<newIndex)
|
||||
}
|
||||
}
|
||||
|
||||
private func commonPrefixUTF16Length(_ a: String, _ b: String) -> 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
|
||||
}
|
||||
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 }
|
||||
// Apply remote text first
|
||||
text = newValue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user