refactor(datagrid): interaction fixes, window UndoManager, multi-cell paste#924
refactor(datagrid): interaction fixes, window UndoManager, multi-cell paste#924
Conversation
There was a problem hiding this comment.
💡 Codex Review
https://github.com/TableProApp/TablePro/blob/c3a0e67c382c58f09c819f9740fb16b82d2eb2d6/Views/Results/Extensions/DataGridView+CellPaste.swift#L13-L15
Handle CRLF when parsing pasted grid
pasteCellsFromClipboard splits only on "\n", so clipboard payloads that use \r\n (common from spreadsheets and browser tables) keep a trailing \r in each last cell value. That \r is then committed to the table, producing hard-to-see corrupted values (e.g., mismatched filters/equality checks after paste). Parse using newline-aware splitting (or trim \r) before commitCellEdit.
https://github.com/TableProApp/TablePro/blob/c3a0e67c382c58f09c819f9740fb16b82d2eb2d6/Views/Results/Extensions/DataGridView+CellPaste.swift#L19
Bound multi-cell paste by the widest parsed row
maxCol is derived from grid.first?.count, which truncates paste when later rows contain more columns than the first row. In irregular TSV input (for example, first line with trimmed trailing empties), valid cells in subsequent rows are silently dropped. Compute bounds per-row during iteration or use the maximum row width across grid.
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Summary
DataGrid audit Phase 3 — interaction fixes, clipboard improvements, and UndoManager unification.
cancelOperation:is now a no-op when not editing.rightMouseDown/menu(for:)overrides fromDataGridFieldEditor. Native text context menu fires during editing.if modifiers.contains(.control)block inkeyDown.DataChangeManageruses a provider for the window'sUndoManagerinstead of a private instance. Removedundo:/redo:selectors fromKeyHandlingTableViewso the responder chain dispatches Cmd+Z to the window's UndoManager.clearChangesAndUndoHistoryusesremoveAllActions(withTarget:)to avoid wiping the editor's undo stack.ClipboardService.writeTabularwrites.string(TSV),public.utf8-tab-separated-values-text, and.html(HTML table). NewHtmlTableEncoderhandles entity escaping.pasteCellsFromClipboard(anchorRow:anchorColumn:)parses clipboard as TSV grid, applies cell-by-cell from the focused cell, wraps inbeginUndoGrouping/endUndoGroupingfor a single Cmd+Z. Falls through to row-append paste when the clipboard isn't a multi-cell grid or no cell is focused.event.modifierFlags.contains(.shift)and callshandleShiftTabKey()which walks to the previous cell, wrapping rows.pasteboardWriterForRowadds.string(TSV) and.htmlalongside the internalrowDragType.Phase 1 landed in #919, Phase 2 in #921.
Test plan
Files
KeyHandlingTableView.swift— removed Ctrl+HJKL, undo:/redo:, Escape behavior; added Shift+Tab; updated paste to try cell-paste firstCellTextField.swift— removedrightMouseDown/menu(for:)fromDataGridFieldEditorDataChangeManager.swift—undoManagerProvider,onUndoAppliedcallback,registerUndohelper, target-scopedremoveAllActionsDataGridCoordinator.swift— removedcanUndo/canRedoMainContentCoordinator.swift— wiresundoManagerProviderandonUndoAppliedMainContentCoordinator+RowOperations.swift—handleUndoResultreplacesundoLastChange/redoLastChangeMainContentCommandActions.swift— undo/redo delegates to window UndoManagerDataTabGridDelegate.swift—dataGridUndo/dataGridRedoare now no-opsRowOperationsManager.swift—applyUndoResultmade internalClipboardService.swift—writeTabular(tsv:html:)methodHtmlTableEncoder.swift(new) — HTML table encoding with entity escapingDataGridView+RowActions.swift—copyRows/copyRowsWithHeadersusewriteTabular; drag adds TSV+HTMLDataGridView+CellPaste.swift(new) —pasteCellsFromClipboardwith undo grouping