Skip to content

Conversation

@charliegiang
Copy link

📝 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
  • cutCells function copies cell data (code, name, config) to the clipboard
  • useDeleteManyCellsSilentCallback hook and deleteCellSilent reducer action to delete cells without pushing to the undo stack.
  • createNewCell extended to accept optional name and config parameters so that pasted cells retain their original names and configurations.

📋 Checklist

  • I have read the contributor guidelines.
  • For large changes, or changes that affect the public API: this change was discussed or approved through an issue, on Discord, or the community discussions (Please provide a link if applicable).
  • Tests have been added for the changes made.
  • Documentation has been updated where applicable, including docstrings for API changes.
  • Pull request title is a good summary of the changes - it will be used in the release notes.
@vercel
Copy link

vercel bot commented Jan 28, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
marimo-docs Ready Ready Preview, Comment Jan 30, 2026 11:11pm

Request Review

@github-actions
Copy link

github-actions bot commented Jan 28, 2026

All contributors have signed the CLA ✍️ ✅
Posted by the CLA Assistant Lite bot.

// 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
Copy link
Author

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
Copy link
Author

@charliegiang charliegiang Jan 28, 2026

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?

@charliegiang
Copy link
Author

I have read the CLA Document and I hereby sign the CLA

@mscolnick
Copy link
Contributor

we originally held off on cut since deleting cells can be super destructive (and cause re-runs).

what is the use-case? it is solely to move cells to another place?

@charliegiang
Copy link
Author

we originally held off on cut since deleting cells can be super destructive (and cause re-runs).

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
  • non-destructive
  • doesn't invalidate downstream cells
  • easy to move cells far apart
  • can move multiple cells at once
@mscolnick
Copy link
Contributor

@charliegiang that is a pretty nice interaction. What do you think @manzt @Light2Dark r.e. UX?

@Light2Dark
Copy link
Contributor

Light2Dark commented Jan 29, 2026

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)

@charliegiang
Copy link
Author

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)

Yeah I agree, how's this?

Unmark cells for cut with esc -> esc

unmark.cell.for.cut.mp4

Undo cut -> paste cells

cut.cells.and.undo.mp4
@manzt
Copy link
Contributor

manzt commented Jan 30, 2026

This is a really nice interaction, and I appreciate the thoughtfulness in evolving it to be non-destructive!

Yeah i think the main benefit would be for bulk moving cells.

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.mov

That 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) {
Copy link
Contributor

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

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

great suggestion, will do

Comment on lines 258 to 273
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.`,
});
};

Copy link
Contributor

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

Copy link
Author

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 👍

const newCellId = action.newCellId || CellId.create();
const insertionIndex = before ? cellIndex : cellIndex + 1;

// Merge provided config with hideCode setting
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Merge provided config with hideCode setting
// Merge provided config with hideCode setting
const mergedConfig = createCellConfig({
...config,
hide_code: Boolean(hideCode || config?.hide_code),
Copy link
Contributor

@Light2Dark Light2Dark Jan 30, 2026

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.

Comment on lines 109 to 125
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();
Copy link
Contributor

@Light2Dark Light2Dark Jan 30, 2026

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.

Copy link
Author

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 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

4 participants