Skip to content

Commit 5343e27

Browse files
authored
refactor(datagrid): drop reloadVersion / lastIdentity counter bridge (#933)
* refactor(datagrid): drop reloadVersion / lastIdentity counter bridge (Phase D) Cell edits, row inserts and removals now drive NSTableView through Delta dispatch directly, so the SwiftUI counter-driven reload path is redundant. Removes: - lastReapplyVersion (already dead) - lastReloadVersion field on TableViewCoordinator - versionChanged branch in reloadAndSyncSelection (delta path already covers this) - reloadVersion field from DataGridIdentity composition - consumeChangedRowIndices on AnyChangeManager / DataChangeManager / StructureChangeManager - changedRowIndices accounting on PendingChanges and StructureChangeManager (14 insert calls and the consume/clear sites) To keep the modified-cell yellow marker correct without the SwiftUI rerun, commitCellEdit and TableViewCoordinator.applyDelta(.cellChanged / .cellsChanged) now call rebuildVisualStateCache before the controller dispatch. This was previously implicit via the versionChanged branch's second reload. Net -259 LOC. Build green, smoke-tested cell edit/undo, add-row, table switch. * chore: ignore .claude/ runtime files * Revert "chore: ignore .claude/ runtime files" .gitignore line * fix(structure): drop empty if-let / for blocks left by Phase D delete sweep The bulk sed deletion of changedRowIndices.insert(...) lines in StructureChangeManager.deleteColumn / deleteIndex / deleteForeignKey left six empty blocks behind: three 'if let rowIndex = workingX.firstIndex(...) { }' blocks where the binding is now unused, and three 'if let rowIndex { for i in rowIndex..<workingX.count { } }' loops with empty bodies. Removed all six.
1 parent 9ef7f19 commit 5343e27

12 files changed

Lines changed: 6 additions & 283 deletions

TablePro/Core/ChangeTracking/AnyChangeManager.swift

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ protocol ChangeManaging: AnyObject {
1919
)
2020
func undoRowDeletion(rowIndex: Int)
2121
func undoRowInsertion(rowIndex: Int)
22-
func consumeChangedRowIndices() -> Set<Int>
2322
}
2423

2524
@Observable
@@ -63,10 +62,6 @@ final class AnyChangeManager {
6362
wrapped.undoRowInsertion(rowIndex: rowIndex)
6463
}
6564

66-
func consumeChangedRowIndices() -> Set<Int> {
67-
wrapped.consumeChangedRowIndices()
68-
}
69-
7065
init(_ manager: any ChangeManaging) {
7166
self.wrapped = manager
7267
}

TablePro/Core/ChangeTracking/DataChangeManager.swift

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -78,12 +78,6 @@ final class DataChangeManager: ChangeManaging {
7878
undoManager.setActionName(actionName)
7979
}
8080

81-
// MARK: - Helper Methods
82-
83-
func consumeChangedRowIndices() -> Set<Int> {
84-
pending.consumeChangedRowIndices()
85-
}
86-
8781
// MARK: - Configuration
8882

8983
func clearChanges() {

TablePro/Core/ChangeTracking/PendingChanges.swift

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ struct PendingChanges: Equatable {
1717
private(set) var insertedRowIndices: Set<Int> = []
1818
private(set) var modifiedCells: [Int: Set<Int>] = [:]
1919
private(set) var insertedRowData: [Int: [String?]] = [:]
20-
private(set) var changedRowIndices: Set<Int> = []
2120

2221
private var changeIndex: [RowChangeKey: Int] = [:]
2322

@@ -77,7 +76,6 @@ struct PendingChanges: Equatable {
7776
if let insertIdx = changeIndex[RowChangeKey(rowIndex: rowIndex, type: .insert)] {
7877
updateInsertedCell(at: insertIdx, columnIndex: columnIndex,
7978
columnName: columnName, newValue: newValue)
80-
changedRowIndices.insert(rowIndex)
8179
return true
8280
}
8381

@@ -93,7 +91,6 @@ struct PendingChanges: Equatable {
9391
changeIndex[updateKey] = changes.count - 1
9492
modifiedCells[rowIndex, default: []].insert(columnIndex)
9593
}
96-
changedRowIndices.insert(rowIndex)
9794
return true
9895
}
9996

@@ -103,7 +100,6 @@ struct PendingChanges: Equatable {
103100
modifiedCells.removeValue(forKey: rowIndex)
104101
appendChange(RowChange(rowIndex: rowIndex, type: .delete, originalRow: originalRow))
105102
deletedRowIndices.insert(rowIndex)
106-
changedRowIndices.insert(rowIndex)
107103
}
108104

109105
mutating func recordRowInsertion(rowIndex: Int, values: [String?]) {
@@ -114,7 +110,6 @@ struct PendingChanges: Equatable {
114110
insertedRowData[rowIndex] = values
115111
appendChange(RowChange(rowIndex: rowIndex, type: .insert, cellChanges: []))
116112
insertedRowIndices.insert(rowIndex)
117-
changedRowIndices.insert(rowIndex)
118113
}
119114

120115
// MARK: - Mutate (cancelling pending edits)
@@ -123,7 +118,6 @@ struct PendingChanges: Equatable {
123118
guard deletedRowIndices.contains(rowIndex) else { return false }
124119
removeChange(rowIndex: rowIndex, type: .delete)
125120
deletedRowIndices.remove(rowIndex)
126-
changedRowIndices.insert(rowIndex)
127121
return true
128122
}
129123

@@ -135,7 +129,6 @@ struct PendingChanges: Equatable {
135129
insertedRowData.removeValue(forKey: rowIndex)
136130

137131
shiftRowIndicesDown(at: rowIndex)
138-
changedRowIndices.insert(rowIndex)
139132
return true
140133
}
141134

@@ -159,7 +152,6 @@ struct PendingChanges: Equatable {
159152
removeChange(rowIndex: rowIndex, type: .insert)
160153
insertedRowIndices.remove(rowIndex)
161154
insertedRowData.removeValue(forKey: rowIndex)
162-
changedRowIndices.insert(rowIndex)
163155
}
164156

165157
let sortedRemoved = validRows.sorted()
@@ -188,7 +180,6 @@ struct PendingChanges: Equatable {
188180
modifiedCells.removeValue(forKey: rowIndex)
189181
appendChange(RowChange(rowIndex: rowIndex, type: .delete, originalRow: originalRow))
190182
deletedRowIndices.insert(rowIndex)
191-
changedRowIndices.insert(rowIndex)
192183
}
193184

194185
/// Re-apply a cell edit during undo replay (skips undo registration).
@@ -213,7 +204,6 @@ struct PendingChanges: Equatable {
213204
if let insertIdx = changeIndex[RowChangeKey(rowIndex: rowIndex, type: .insert)] {
214205
updateInsertedCell(at: insertIdx, columnIndex: columnIndex,
215206
columnName: columnName, newValue: newValue)
216-
changedRowIndices.insert(rowIndex)
217207
return
218208
}
219209

@@ -229,7 +219,6 @@ struct PendingChanges: Equatable {
229219
changeIndex[updateKey] = changes.count - 1
230220
modifiedCells[rowIndex, default: []].insert(columnIndex)
231221
}
232-
changedRowIndices.insert(rowIndex)
233222
}
234223

235224
/// Replace an inserted row's cell value during undo replay (no shift, no undo).
@@ -241,7 +230,6 @@ struct PendingChanges: Equatable {
241230
) {
242231
guard let insertIdx = changeIndex[RowChangeKey(rowIndex: rowIndex, type: .insert)] else { return }
243232
updateInsertedCell(at: insertIdx, columnIndex: columnIndex, columnName: columnName, newValue: newValue)
244-
changedRowIndices.insert(rowIndex)
245233
}
246234

247235
/// Restore a cell's value during undo replay when an existing change matches.
@@ -274,7 +262,6 @@ struct PendingChanges: Equatable {
274262
newValue: previousValue
275263
)
276264
}
277-
changedRowIndices.insert(rowIndex)
278265
}
279266

280267
/// Insert a synthetic .insert RowChange for undo replay (e.g., after redoing a deletion's undo).
@@ -291,7 +278,6 @@ struct PendingChanges: Equatable {
291278
if let savedValues {
292279
insertedRowData[rowIndex] = savedValues
293280
}
294-
changedRowIndices.insert(rowIndex)
295281
}
296282

297283
/// Insert a batch of rows (for undo replay of a batch deletion's undo).
@@ -314,7 +300,6 @@ struct PendingChanges: Equatable {
314300
changes.append(RowChange(rowIndex: rowIndex, type: .insert, cellChanges: cellChanges))
315301
insertedRowIndices.insert(rowIndex)
316302
insertedRowData[rowIndex] = values
317-
changedRowIndices.insert(rowIndex)
318303
}
319304
rebuildChangeIndex()
320305
}
@@ -338,23 +323,14 @@ struct PendingChanges: Equatable {
338323
insertedRowIndices.removeAll()
339324
modifiedCells.removeAll()
340325
insertedRowData.removeAll()
341-
changedRowIndices.removeAll()
342326
}
343327

344-
mutating func consumeChangedRowIndices() -> Set<Int> {
345-
let indices = changedRowIndices
346-
changedRowIndices.removeAll()
347-
return indices
348-
}
349-
350-
/// Replace internal state from a serialized snapshot.
351328
mutating func restore(from snapshot: TabChangeSnapshot) {
352329
changes = snapshot.changes
353330
deletedRowIndices = snapshot.deletedRowIndices
354331
insertedRowIndices = snapshot.insertedRowIndices
355332
modifiedCells = snapshot.modifiedCells
356333
insertedRowData = snapshot.insertedRowData
357-
changedRowIndices = []
358334
rebuildChangeIndex()
359335
}
360336

@@ -471,7 +447,6 @@ struct PendingChanges: Equatable {
471447
if changes[updateIdx].cellChanges.isEmpty {
472448
removeChangeAt(updateIdx)
473449
}
474-
changedRowIndices.insert(rowIndex)
475450
return true
476451
}
477452

@@ -494,7 +469,6 @@ struct PendingChanges: Equatable {
494469
}
495470
modifiedCells = newModifiedCells
496471

497-
changedRowIndices = Set(changedRowIndices.map { $0 >= insertionPoint ? $0 + 1 : $0 })
498472
rebuildChangeIndex()
499473
}
500474

TablePro/Core/SchemaTracking/StructureChangeManager.swift

Lines changed: 0 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,6 @@ final class StructureChangeManager: ChangeManaging {
1818
var hasChanges: Bool { !pendingChanges.isEmpty }
1919
var reloadVersion: Int = 0
2020

21-
// Track which rows changed since last reload for granular updates
22-
private(set) var changedRowIndices: Set<Int> = []
23-
2421
// Current state (loaded from database)
2522
private(set) var currentColumns: [EditableColumnDefinition] = []
2623
private(set) var currentIndexes: [EditableIndexDefinition] = []
@@ -48,13 +45,6 @@ final class StructureChangeManager: ChangeManaging {
4845
var canUndo: Bool { undoManager.canUndo }
4946
var canRedo: Bool { undoManager.canRedo }
5047

51-
/// Consume and clear changed row indices (for granular table reloads)
52-
func consumeChangedRowIndices() -> Set<Int> {
53-
let indices = changedRowIndices
54-
changedRowIndices.removeAll()
55-
return indices
56-
}
57-
5848
// MARK: - Load Schema
5949

6050
func loadSchema(
@@ -260,9 +250,6 @@ final class StructureChangeManager: ChangeManaging {
260250
undoManager.setActionName(String(localized: "Delete Column"))
261251
pendingChanges[key] = .deleteColumn(column)
262252
trackChangeKey(key)
263-
if let rowIndex = workingColumns.firstIndex(where: { $0.id == id }) {
264-
changedRowIndices.insert(rowIndex)
265-
}
266253
} else {
267254
let rowIndex = workingColumns.firstIndex(where: { $0.id == id })
268255
if let column = workingColumns.first(where: { $0.id == id }) {
@@ -271,11 +258,6 @@ final class StructureChangeManager: ChangeManaging {
271258
}
272259
undoManager.setActionName(String(localized: "Delete Column"))
273260
}
274-
if let rowIndex {
275-
for i in rowIndex..<workingColumns.count {
276-
changedRowIndices.insert(i)
277-
}
278-
}
279261
workingColumns.removeAll { $0.id == id }
280262
pendingChanges.removeValue(forKey: key)
281263
untrackChangeKey(key)
@@ -333,9 +315,6 @@ final class StructureChangeManager: ChangeManaging {
333315
undoManager.setActionName(String(localized: "Delete Index"))
334316
pendingChanges[key] = .deleteIndex(index)
335317
trackChangeKey(key)
336-
if let rowIndex = workingIndexes.firstIndex(where: { $0.id == id }) {
337-
changedRowIndices.insert(rowIndex)
338-
}
339318
} else {
340319
let rowIndex = workingIndexes.firstIndex(where: { $0.id == id })
341320
if let index = workingIndexes.first(where: { $0.id == id }) {
@@ -344,11 +323,6 @@ final class StructureChangeManager: ChangeManaging {
344323
}
345324
undoManager.setActionName(String(localized: "Delete Index"))
346325
}
347-
if let rowIndex {
348-
for i in rowIndex..<workingIndexes.count {
349-
changedRowIndices.insert(i)
350-
}
351-
}
352326
workingIndexes.removeAll { $0.id == id }
353327
pendingChanges.removeValue(forKey: key)
354328
untrackChangeKey(key)
@@ -406,9 +380,6 @@ final class StructureChangeManager: ChangeManaging {
406380
undoManager.setActionName(String(localized: "Delete Foreign Key"))
407381
pendingChanges[key] = .deleteForeignKey(fk)
408382
trackChangeKey(key)
409-
if let rowIndex = workingForeignKeys.firstIndex(where: { $0.id == id }) {
410-
changedRowIndices.insert(rowIndex)
411-
}
412383
} else {
413384
let rowIndex = workingForeignKeys.firstIndex(where: { $0.id == id })
414385
if let fk = workingForeignKeys.first(where: { $0.id == id }) {
@@ -417,11 +388,6 @@ final class StructureChangeManager: ChangeManaging {
417388
}
418389
undoManager.setActionName(String(localized: "Delete Foreign Key"))
419390
}
420-
if let rowIndex {
421-
for i in rowIndex..<workingForeignKeys.count {
422-
changedRowIndices.insert(i)
423-
}
424-
}
425391
workingForeignKeys.removeAll { $0.id == id }
426392
pendingChanges.removeValue(forKey: key)
427393
untrackChangeKey(key)
@@ -552,7 +518,6 @@ final class StructureChangeManager: ChangeManaging {
552518
pendingChanges.removeAll()
553519
changeOrder.removeAll()
554520
validationErrors.removeAll()
555-
changedRowIndices.removeAll()
556521
resetWorkingState()
557522
reloadVersion += 1
558523
rebuildVisualStateCache()

TablePro/Views/Results/DataGridCoordinator.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,6 @@ final class TableViewCoordinator: NSObject, NSTableViewDelegate, NSTableViewData
6161
@Binding var selectedRowIndices: Set<Int>
6262

6363
var lastIdentity: DataGridIdentity?
64-
var lastReloadVersion: Int = 0
65-
var lastReapplyVersion: Int = -1
6664
private(set) var cachedRowCount: Int = 0
6765
private(set) var cachedColumnCount: Int = 0
6866
private(set) var enumOrSetColumns: Set<Int> = []
@@ -340,6 +338,7 @@ final class TableViewCoordinator: NSObject, NSTableViewDelegate, NSTableViewData
340338
guard row >= 0, row < tableView.numberOfRows else { return }
341339
guard tableColumn >= 0, tableColumn < tableView.numberOfColumns else { return }
342340
invalidateDisplayCache(forDisplayRow: row, column: column)
341+
rebuildVisualStateCache()
343342
tableView.reloadData(
344343
forRowIndexes: IndexSet(integer: row),
345344
columnIndexes: IndexSet(integer: tableColumn)
@@ -359,6 +358,7 @@ final class TableViewCoordinator: NSObject, NSTableViewDelegate, NSTableViewData
359358
invalidateDisplayCache(forDisplayRow: position.row, column: position.column)
360359
}
361360
guard !rowSet.isEmpty, !colSet.isEmpty else { return }
361+
rebuildVisualStateCache()
362362
tableView.reloadData(forRowIndexes: rowSet, columnIndexes: colSet)
363363
case .rowsInserted(let indices):
364364
guard !indices.isEmpty else { return }

TablePro/Views/Results/DataGridView.swift

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ struct RowVisualState {
2323
}
2424

2525
struct DataGridIdentity: Equatable {
26-
let reloadVersion: Int
2726
let schemaVersion: Int
2827
let metadataVersion: Int
2928
let paginationVersion: Int
@@ -35,9 +34,8 @@ struct DataGridIdentity: Equatable {
3534
let primaryKeyColumns: [String]
3635
let hiddenColumns: Set<String>
3736

38-
init(reloadVersion: Int, schemaVersion: Int, metadataVersion: Int, paginationVersion: Int,
37+
init(schemaVersion: Int, metadataVersion: Int, paginationVersion: Int,
3938
rowCount: Int, columnCount: Int, isEditable: Bool, configuration: DataGridConfiguration) {
40-
self.reloadVersion = reloadVersion
4139
self.schemaVersion = schemaVersion
4240
self.metadataVersion = metadataVersion
4341
self.paginationVersion = paginationVersion
@@ -233,7 +231,6 @@ struct DataGridView: NSViewRepresentable {
233231
let columnCount = latestRows.columns.count
234232

235233
let currentIdentity = DataGridIdentity(
236-
reloadVersion: changeManager.reloadVersion,
237234
schemaVersion: schemaVersion,
238235
metadataVersion: metadataVersion,
239236
paginationVersion: paginationVersion,
@@ -262,7 +259,6 @@ struct DataGridView: NSViewRepresentable {
262259
tableView.usesAlternatingRowBackgroundColors = settings.showAlternateRows
263260
}
264261

265-
let versionChanged = coordinator.lastReloadVersion != changeManager.reloadVersion
266262
let metadataChanged = previousIdentity.map { $0.metadataVersion != metadataVersion } ?? false
267263
let oldRowCount = coordinator.cachedRowCount
268264
let oldColumnCount = coordinator.cachedColumnCount
@@ -328,7 +324,6 @@ struct DataGridView: NSViewRepresentable {
328324
coordinator: coordinator,
329325
tableRows: latestRows,
330326
needsFullReload: needsFullReload,
331-
versionChanged: versionChanged,
332327
metadataChanged: metadataChanged,
333328
paginationChanged: paginationChanged
334329
)
@@ -502,7 +497,6 @@ struct DataGridView: NSViewRepresentable {
502497
coordinator: TableViewCoordinator,
503498
tableRows: TableRows,
504499
needsFullReload: Bool,
505-
versionChanged: Bool,
506500
metadataChanged: Bool = false,
507501
paginationChanged: Bool = false
508502
) {
@@ -527,21 +521,8 @@ struct DataGridView: NSViewRepresentable {
527521
tableView.reloadData(forRowIndexes: visibleRows, columnIndexes: fkColumnIndices)
528522
}
529523
}
530-
} else if versionChanged {
531-
let changedRows = changeManager.consumeChangedRowIndices()
532-
if changedRows.count > 500 {
533-
tableView.reloadData()
534-
} else if !changedRows.isEmpty {
535-
let rowIndexSet = IndexSet(changedRows)
536-
let columnIndexSet = IndexSet(integersIn: 0..<tableView.numberOfColumns)
537-
tableView.reloadData(forRowIndexes: rowIndexSet, columnIndexes: columnIndexSet)
538-
} else if !changeManager.hasChanges {
539-
tableView.reloadData()
540-
}
541524
}
542525

543-
coordinator.lastReloadVersion = changeManager.reloadVersion
544-
545526
if paginationChanged && tableView.numberOfRows > 0 {
546527
tableView.scrollRowToVisible(0)
547528
}

0 commit comments

Comments
 (0)