Skip to content

Fix visual-block delete clobbering the unnamed register - #57

Open
ikshantshukla123 wants to merge 3 commits into
unstablebuild:mainfrom
ikshantshukla123:fix-visual-block-delete-paste
Open

Fix visual-block delete clobbering the unnamed register#57
ikshantshukla123 wants to merge 3 commits into
unstablebuild:mainfrom
ikshantshukla123:fix-visual-block-delete-paste

Conversation

@ikshantshukla123

Copy link
Copy Markdown

Visual-block d/x followed by p/P reinserted only the last row of
the block.

copySelectionForDelete writes the full block correctly, but the delete
runs one edit per row and each edit notifies the copy-on-delete
subscriber, which overwrites the register per row. The visual d/x
path now re-asserts the copied block once the delete completes, scoped
to block selections only. This also stops "_d on a block from touching
unnamed.

Fixes #1.

Regression test TestVisualBlockDeleteThenPaste (full-Vi level, where
the subscriber is installed): d then P, x then p, a ragged
block, and black-hole preservation : each checks register text, block
mode metadata, and the pasted buffer. The test fails on main with only
the last row in the register.

A block delete runs one edit per row, so re-assert the copied block after it completes.

Signed-off-by: ikshantshukla123 <ikshankshukla44@gmail.com>
@codecov

codecov Bot commented Sep 12, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

A failing clipboard must not break the delete; it only skips the restore.

Signed-off-by: ikshantshukla123 <ikshankshukla44@gmail.com>
@ikshantshukla123

ikshantshukla123 commented Sep 12, 2026

Copy link
Copy Markdown
Author

Note on scope: this resolves the two writer conflict in the visual d/x path (the explicit copy wins over the per row copyon delete writes) rather than restructuring the per row notifications in DeleteBlockContext/delClip. that keeps the blast radius to vi flows the structural fix (block transactions for usage subscribers) would also touch Repeater and fits better as a follow up if you want it? @ernestrc

@ernestrc

Copy link
Copy Markdown
Contributor

Thanks for taking this! I gave you the green light on your approach but upon reviewing your PR, I saw an approach that avoids the need to correct the contents of the unnamedRegister. delClip is installed with *Vi as a clipboard implementation, allowing us to intercept calls and it's currently used to make sure undo/redo deletes are not copied to the clipboard, as well as backspace deletes in insert mode.

We can add a new method to viHandler that then we can call in Vi.Copy:

type viHandler interface {
        ...
>>	copySuppressed() bool
}

Then set a boolean in viHandler that changes the return value of this new method, so while we're doing block operations in s/c visual selection, in handleVisualBlockChangeStart and d/x visual selection we don't call the underlying clipboard's Copy, preventing the clobbering.

From a maintainability's point of view, I'd rather avoid an undesired behavior than amending the outcome of it.

Suppress per-row clipboard writes so the explicit block copy is the only one that lands.

Signed-off-by: ikshantshukla123 <ikshankshukla44@gmail.com>
@ikshantshukla123

Copy link
Copy Markdown
Author

Thanks for taking this! I gave you the green light on your approach but upon reviewing your PR, I saw an approach that avoids the need to correct the contents of the unnamedRegister. delClip is installed with *Vi as a clipboard implementation, allowing us to intercept calls and it's currently used to make sure undo/redo deletes are not copied to the clipboard, as well as backspace deletes in insert mode.

We can add a new method to viHandler that then we can call in Vi.Copy:

type viHandler interface {
        ...
>>	copySuppressed() bool
}

Then set a boolean in viHandler that changes the return value of this new method, so while we're doing block operations in s/c visual selection, in handleVisualBlockChangeStart and d/x visual selection we don't call the underlying clipboard's Copy, preventing the clobbering.

From a maintainability's point of view, I'd rather avoid an undesired behavior than amending the outcome of it.

Thanks for more clarity on requirment @ernestrc
Done switched to suppression as suggested copySuppressed() on the viHandler interface, held during the block deletes in visual d/x (block-scoped) and handleVisualBlockChangeStart, gated in Vi.Copy next to the existing guards. The save/restore and its error path test are gone; the regression test is unchanged and green, plus a small test pinning that block c leaves unnamed alone.

@ernestrc

Copy link
Copy Markdown
Contributor

The reported workspace/explorer, startup race, OAuth EOF, and storage failover failures are addressed in follow-up #65 (with upstream OAuth fix unstablebuild/blue#3). These fixes are separate from the visual-block editing change here. Deterministic regressions and 50 repeated race-enabled runs of the affected tests pass locally; #65 CI is running.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

vi: visual-block delete then paste only reinserts the last row

2 participants