-
Notifications
You must be signed in to change notification settings - Fork 892
feat: add cut cells command (#7423) #8019
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
feat: add cut cells command (#7423) #8019
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
All contributors have signed the CLA ✍️ ✅ |
| // NOTE: We don't support Cut yet. We can wait for feedback before implementing. | ||
| // It is a bit more complex as will need to: | ||
| // - include id, outputs, and name | ||
| // - delete the existing cell, but don't place on the undo stack |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
throughout my testing this actually felt a bit unintuitive. should users be able to undo a cut?
| // It is a bit more complex as will need to: | ||
| // - include id, outputs, and name | ||
| // - delete the existing cell, but don't place on the undo stack | ||
| // - don't want to invalidate downstream cells |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is unavoidable in my current implementation.
What might be worth considering though is a "pending" state where we grey out the cell -> paste -> use dropCellOverCell to preserve cellId ? thoughts?
|
I have read the CLA Document and I hereby sign the CLA |
|
we originally held off on what is the use-case? it is solely to move cells to another place? |
Yeah i think the main benefit would be for bulk moving cells. How about something like this? cut.cells.pending.mp4
|
|
@charliegiang that is a pretty nice interaction. What do you think @manzt @Light2Dark r.e. UX? |
|
That looks pretty good imo @charliegiang, I'm guessing just a styling change to mark the cell as 'cut'. And on refresh or cell runs it would be as normal. I think there should be a way to remove the cut as well (maybe Esc) |
90b5709 to
1b48033
Compare
for more information, see https://pre-commit.ci
Yeah I agree, how's this? Unmark cells for cut with esc -> esc unmark.cell.for.cut.mp4Undo cut -> paste cells cut.cells.and.undo.mp4 |
|
This is a really nice interaction, and I appreciate the thoughtfulness in evolving it to be non-destructive!
Since the original use case mentioned is moving cells around, I just wanted to point out that we do have bulk move in "command mode." You can select multiple cells and use move up/down or send to top/bottom. Screen.Recording.2026-01-30.at.11.38.21.AM.movThat said, I think cut really shines for moving cells between notebooks or applications, where the clipboard-based approach makes a lot of sense. |
| const { before = false } = opts ?? {}; | ||
|
|
||
| // Check if we have pending cut cells (internal move) | ||
| if (pendingCutState.cellIds.size > 0) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe copyCells should clear pendingCutState? To overwrite the cut
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
great suggestion, will do
| const toastCutSuccess = (cellLength: number) => { | ||
| const cellText = cellLength === 1 ? "Cell" : `${cellLength} cells`; | ||
| toast({ | ||
| title: `${cellText} marked for cut`, | ||
| description: `${cellText} will be moved on paste.`, | ||
| }); | ||
| }; | ||
|
|
||
| const toastPasteSuccess = (cellLength: number) => { | ||
| const cellText = cellLength === 1 ? "Cell" : `${cellLength} cells`; | ||
| toast({ | ||
| title: `${cellText} moved`, | ||
| description: `${cellText} ${cellLength === 1 ? "has" : "have"} been moved.`, | ||
| }); | ||
| }; | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Better to remove these toasts? It's quite visual that the cut & move took place I think
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks, wanted to keep it inline with the other interactions but i agree here 👍
frontend/src/core/cells/cells.ts
Outdated
| const newCellId = action.newCellId || CellId.create(); | ||
| const insertionIndex = before ? cellIndex : cellIndex + 1; | ||
|
|
||
| // Merge provided config with hideCode setting |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| // Merge provided config with hideCode setting |
frontend/src/core/cells/cells.ts
Outdated
| // Merge provided config with hideCode setting | ||
| const mergedConfig = createCellConfig({ | ||
| ...config, | ||
| hide_code: Boolean(hideCode || config?.hide_code), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This would return true if hideCode is set to false but config is true. Not sure if there are side effects of that 🤔. Or at the call site (createNewCell clipboard), pass in hideCode.
| const clipboardData: ClipboardCellData = { | ||
| cells: cells.map((cell) => ({ | ||
| code: cell.code, | ||
| name: cell.name, | ||
| config: cell.config, | ||
| })), | ||
| version: "1.0", | ||
| }; | ||
|
|
||
| // Create plain text representation (joined by newlines) | ||
| const plainText = cells.map((cell) => cell.code).join("\n\n"); | ||
|
|
||
| // Create clipboard item with both custom mimetype and plain text | ||
| const clipboardItem = new ClipboardItemBuilder() | ||
| .add(MARIMO_CELL_MIMETYPE, clipboardData) | ||
| .add("text/plain", plainText) | ||
| .build(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think there's some repeated code with copyCells? Makes sense to do this there too imo.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yep nice callout. i meant to go back and DRY this up, slipped my mind. thanks for the reminder 👍
📝 Summary
Added the ability to cut cells in command mode, which copies cells to clipboard and deletes them.
Partially addresses #7423
nits / super nits encouraged 🙂
🔍 Description of Changes
cut.cells.mp4
cutCellsfunction copies cell data (code, name, config) to the clipboarduseDeleteManyCellsSilentCallbackhook anddeleteCellSilentreducer action to delete cells without pushing to the undo stack.createNewCellextended to accept optional name and config parameters so that pasted cells retain their original names and configurations.📋 Checklist