perf(editor): apply native edit source to line index

This commit is contained in:
Feror 2026-05-30 19:28:34 +02:00
parent 525691693b
commit f62d59d621
5 changed files with 40 additions and 21 deletions

View file

@ -156,10 +156,16 @@ public struct DocumentLineIndex: Hashable, Sendable {
public mutating func replace(_ edit: DocumentLineIndexEdit) -> DocumentLineIndexEditResult {
let oldSource = source as NSString
let oldLength = oldSource.length
let range = NSRange(
location: max(0, min(edit.range.location, oldLength)),
length: max(0, min(edit.range.length, oldLength - max(0, min(edit.range.location, oldLength))))
)
let range = clampedRange(edit.range, sourceLength: oldLength)
let updatedSource = oldSource.replacingCharacters(in: range, with: edit.replacement)
return replace(edit, updatedSource: updatedSource)
}
@discardableResult
public mutating func replace(_ edit: DocumentLineIndexEdit, updatedSource: String) -> DocumentLineIndexEditResult {
let oldSource = source as NSString
let oldLength = oldSource.length
let range = clampedRange(edit.range, sourceLength: oldLength)
let replacement = edit.replacement
let replacementLength = (replacement as NSString).length
let locationDelta = replacementLength - range.length
@ -172,7 +178,7 @@ public struct DocumentLineIndex: Hashable, Sendable {
let scanStart = boundaries[lowerLineIndex].contentRange.location
let oldScanEnd = boundaries[upperLineIndex].nextLineLocation
source = oldSource.replacingCharacters(in: range, with: replacement)
source = updatedSource
let newSource = source as NSString
let newScanEnd = max(scanStart, min(newSource.length, oldScanEnd + locationDelta))
@ -202,6 +208,14 @@ public struct DocumentLineIndex: Hashable, Sendable {
)
}
private func clampedRange(_ range: NSRange, sourceLength: Int) -> NSRange {
let location = max(0, min(range.location, sourceLength))
return NSRange(
location: location,
length: max(0, min(range.length, sourceLength - location))
)
}
private func editorLine(for boundary: DocumentLineBoundary, activeLineIndex: Int) -> EditorLine {
let nsSource = source as NSString
return EditorLine(

View file

@ -124,8 +124,12 @@ public struct EditorState: Hashable, Sendable {
activeLineIndex = lineIndex.lineIndex(containing: selection.location)
}
public mutating func updateSource(_ edit: DocumentLineIndexEdit, selection newSelection: EditorSelection? = nil) {
lineIndex.replace(edit)
public mutating func updateSource(
_ source: String,
edit: DocumentLineIndexEdit,
selection newSelection: EditorSelection? = nil
) {
lineIndex.replace(edit, updatedSource: source)
document.source = lineIndex.source
selection = EditorActiveLineTracker.clampedSelection(newSelection ?? selection, in: document.source)
activeLineIndex = lineIndex.lineIndex(containing: selection.location)

View file

@ -178,7 +178,7 @@ public enum EditorBenchmarkProfiler {
)
let changedSource = sourceByInsertingProbeText(in: source, at: midpoint)
var changedLineIndex = lineIndex
changedLineIndex.replace(typingEdit)
changedLineIndex.replace(typingEdit, updatedSource: changedSource)
let changedActiveLineIndex = changedLineIndex.lineIndex(containing: midpoint + 1)
let activeLineResult = measure {
@ -221,7 +221,8 @@ public enum EditorBenchmarkProfiler {
let sourceUpdateResult = measure {
var updatedState = state
updatedState.updateSource(
typingEdit,
changedSource,
edit: typingEdit,
selection: EditorSelection(location: midpoint + typingEdit.replacementUTF16Length, length: 0)
)
}

View file

@ -54,7 +54,7 @@ public final class HybridMarkdownEditorViewModel: ObservableObject, EditorCoordi
guard state.document.source != source else { return }
let previousActiveLineIndex = state.activeLineIndex
if let edit {
state.updateSource(edit, selection: selection)
state.updateSource(source, edit: edit, selection: selection)
} else {
state.updateSource(source)
if let selection {
@ -286,7 +286,7 @@ private struct NativeMarkdownTextView: NSViewRepresentable {
let selection = EditorSelection(range: textView.selectedRange())
let edit = pendingEdit
if let edit {
currentLineIndex.replace(edit)
currentLineIndex.replace(edit, updatedSource: textView.string)
} else {
currentLineIndex = DocumentLineIndex(source: textView.string)
}
@ -515,7 +515,7 @@ private struct NativeMarkdownTextView: UIViewRepresentable {
let selection = EditorSelection(range: textView.selectedRange)
let edit = pendingEdit
if let edit {
currentLineIndex.replace(edit)
currentLineIndex.replace(edit, updatedSource: textView.text)
} else {
currentLineIndex = DocumentLineIndex(source: textView.text)
}

View file

@ -7,6 +7,15 @@ struct BenchmarkScenario {
var url: URL
}
let trackedInteractionMetricNames = [
"active_line_lookup",
"selection_update",
"dirty_line_invalidation_click",
"typing_state_update",
"dirty_line_invalidation_typing",
"render_update_typing_dirty"
]
let arguments = Array(CommandLine.arguments.dropFirst())
let repositoryRoot = URL(fileURLWithPath: FileManager.default.currentDirectoryPath, isDirectory: true)
@ -99,15 +108,6 @@ func printScenario(name: String, result: EditorBenchmarkResult) {
print("")
}
let trackedInteractionMetricNames = [
"active_line_lookup",
"selection_update",
"dirty_line_invalidation_click",
"typing_state_update",
"dirty_line_invalidation_typing",
"render_update_typing_dirty"
]
func format(_ value: Double) -> String {
String(format: "%.3f", value)
}