feat(inspector): split and merge columns in the CSV editor#1941
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9b42ef2038
ℹ️ 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".
| presentInvalidPattern() | ||
| return | ||
| } | ||
| inspectorDocument?.splitColumn(at: column, separator: separator, isRegex: isRegex) |
There was a problem hiding this comment.
Rebase active filters and sorts after splitting
When a filter or sort currently targets a column to the right of the split, its stored integer index is not shifted after this call. recomputeDisplay() subsequently builds predicates from those stale indices, so the active filter/sort operates on a newly created or preceding column rather than the original data; Merge has the analogous left-shift problem. Rebase or clear state.filters and state.sortState whenever these schema changes occur.
Useful? React with 👍 / 👎.
| private func recomputeInferredTypes() { | ||
| let sample = store.pageRows(offset: 0, limit: Self.typeInferenceSampleSize) | ||
| inferredTypes = CSVTypeInferrer.inferColumns(rows: sample, columnCount: store.columnCount) | ||
| typeOverrides = [:] |
There was a problem hiding this comment.
Preserve type overrides on untouched columns
A split or merge invokes this method and clears every manual type override, including overrides on columns unrelated to the operation. For example, splitting column A removes a user-selected type for column C and can change its subsequent sort behavior; retain unaffected overrides and shift their indices while replacing only the structurally affected ones.
Useful? React with 👍 / 👎.
922879e to
06c60c1
Compare
9b42ef2 to
8faf1f6
Compare
|
Addressed a code review. Findings and fixes:
|
06c60c1 to
88c3e26
Compare
8faf1f6 to
9dd6e93
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9dd6e936d8
ℹ️ 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".
| regex.enumerateMatches(in: value, range: NSRange(location: 0, length: text.length)) { match, _, _ in | ||
| guard let match, match.range.length > 0 else { return } |
There was a problem hiding this comment.
Handle zero-width regex separators
When users choose Regex mode with a valid zero-width separator such as (?=,), ^, or a lookahead/lookbehind, this guard skips every match and returns the original value as one piece. The UI promises to split at every regex match, so these commonly useful boundary patterns silently produce no split; process zero-length matches while advancing safely instead of discarding them.
Useful? React with 👍 / 👎.
9dd6e93 to
d22b41d
Compare
|
Preview deployment for your docs. Learn more about Mintlify Previews.
💡 Tip: Enable Workflows to automatically generate PRs for you. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d22b41d309
ℹ️ 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".
| let pieceCount = inspector.columnNames.count - oldCount + 1 | ||
| let upper = min(column + max(pieceCount, 0), inspector.columnNames.count) | ||
| let newNames = column < upper ? Array(inspector.columnNames[column..<upper]) : [] | ||
| replaceLayoutKey(oldName, with: newNames) |
There was a problem hiding this comment.
Restore column layout when undoing structural edits
When the user has a custom column order, widths, or hidden columns, this mutates state.columnLayout outside the document undo operation. Cmd-Z restores only the CSV snapshot, so after undoing a split the layout still contains the generated piece names and the restored original column is appended with default visibility/width; merge similarly drops the restored right-hand column's layout state. Register an inverse layout update with the same undo step (or restore a layout snapshot) so the advertised single undo fully restores the editor state.
Useful? React with 👍 / 👎.
|
Preview deployment for your docs. Learn more about Mintlify Previews.
💡 Tip: Enable Workflows to automatically generate PRs for you. |
Part 3 of 4 toward #1469 (CSV structural editing). Focused on Split / Merge. Stacked on #1940 (base branch
feat/1469-csv-column-editing).What
<column> 1,<column> 2, ...Why
#1469 asks for split/merge as first-class column verbs, matching Tablecruncher (its
csvmenu.cppSplit/Merge dialogs), Modern CSV, and the Text-to-Columns / Join conventions from Excel and Sheets.How (native / HIG)
CSVRowStore.splitColumn(at:spec:)/mergeColumns(at:separator:)primitives. Because a split changes the column count per row, these materialize the affected rows (the lazy byte-range transform log can't express a split), then resync the header row and clear the transform log. This is edit-mode only; large read-only files are a separate concern (feat(csv): read-only mode for files past a size threshold (memory-mapped / DuckDB-backed) #1472).components(separatedBy:)) or a compiledNSRegularExpression, chosen in the dialog via anNSSegmentedControl. An invalid regex shows an error and does nothing.NSAlertsheets with an accessory view, matching the existing rename/insert-column prompt. Column layout stays correct because the grid already tolerates a stalecolumnOrder(unknown names skipped, new columns appended).splitColumn/mergeColumnsare added to theInspectorDocumentprotocol with default no-op implementations. This is an additive PluginKit change (Library Evolution fills the default for existing conformers), so nocurrentPluginKitVersionbump.Tests
CSVRowStore.split(_:spec:)for literal and regex separators;splitColumnpadding;mergeColumnsjoining;captureState/restoreround-trip.InspectorColumnMenuBuilder: Split/Merge wiring, and Merge omitted for the last column.Docs / changelog
docs/features/csv-inspector.mdxcolumn-operations section updated.[Unreleased].Needs a local Xcode build to confirm compilation. PluginKit change is additive (new protocol requirements with defaults); no version bump.