jake-stewart / multicursor.nvim

multiple cursors in neovim
MIT License
617 stars 5 forks source link

Inconsistent behavior when deleting lines depending on which cursor is the main cursor #50

Closed RAV64 closed 1 month ago

RAV64 commented 1 month ago

https://github.com/user-attachments/assets/7640e0c5-d06e-4d5a-a9e7-f4e94e4b4036

The first example here deletes one more additional line than expected. The command I'm using is "dk" when the main cursor is on the second a. I would not expect the function closing "}" line to also be deleted.

RAV64 commented 1 month ago

Actually - I would not expect any of these commands to delete any of the comments at all either.

RAV64 commented 1 month ago

https://github.com/user-attachments/assets/36c41ea1-693d-4070-aa7d-c8e80147b9a6

Here is an example of how these two deleting directions work in Helix editor.

jake-stewart commented 1 month ago

because the main cursor executes first, it deletes the other cursor's line, moving it.

ideally i would perform for each cursor from top to bottom, instead of main cursor first.

one approach would be after every command just undo it and then do it for every cursor top to bottom. what would be better is if i can find a way to identify what was deleted and apply that to affected cursors

RAV64 commented 1 month ago

There's so many little complexities like this. I wonder how the official multicursor implementation will deal with all of it. So many decisions to make on whats expected behavior and whats not..

You're doing magic work - This is one of my favorite plugins, thanks for refining it so actively 😄

jake-stewart commented 1 month ago

i imagine the official multicursor implementation will not be a lua hack.

thanks im glad you like it

jake-stewart commented 1 month ago

Screen.Recording.2024-10-02.at.5.26.50.mov Here is an example of how these two deleting directions work in Helix editor.

looks like the second cursor does nothing - perhaps if the line a cursor is on gets deleted, so does the cursor. i wonder if this is possible

RAV64 commented 1 month ago

There's couple ways to look at it. In both cases in the helix example both cursors are doing something. One of them deletes 1 line and another 2 lines if this was translated into Neovim. I'm not sure which way to think about this would be better

a. the further away cursor from the move direction deletes its own line and the closer cursor deletes own and next. b. the further away cursor deletes own line and the next line, and the closer cursor only the next line.

Could you save all the lines to be deleted in a list, remove duplicates and then iterate that list from end of file to the beginning deleting each line once even if multiple cursors applied on it?

RAV64 commented 1 month ago

https://github.com/user-attachments/assets/b250da11-be64-4ad0-97df-9bc62bb237ce

One way to accomplish this would be doing something like Vjd when command like dj is issued?

jake-stewart commented 1 month ago

the way it's implemented is you run dk and then once neovim finishes executing it, neovim reaches a safe state and executes SafeState autocommand. from here, i iterate over every cursor, updating its extmark position and rerunning dk with vim.api.nvim_feedkeys. i don't keep track of anything which is good because then vim commands are executed correctly instead of being simulated.

i may be able to play around with the range between vim.fn.getcurpos() and vim.fn.getpos("'[") to find affected cursors.

jake-stewart commented 1 month ago

looks like the best approach is to check whether the file has changed with changed tick & whether number of lines has decreased. if so, undo the last change and repeat from the first cursor down. then, after each cursor invocation, can check whether number of lines decreased.

it seems to work so far but i'll have to make sure it's not buggy. i doubt ill end up adding that 3 line deletion when you have 2 cursors and press dj. either 4 lines or 2 lines. (either both cursors perform, or the second is deleted by the first). will see what happens

RAV64 commented 1 month ago

For what its worth - if the end result is consistent between all the cursors I think that's good enough. Inconsistency between cursors is worst possible outcome since that forces you to start again or fix manually.

jake-stewart commented 1 month ago

@RAV64 should be fixed. now always performs from top to bottom if change is detected. cursors should be consistent. let me know if any problems

while testing this i noticed a bug that undoing does not restore cursors that were merged. i will fix later

jake-stewart commented 1 month ago

@RAV64 should be fixed. now always performs from top to bottom if change is detected. cursors should be consistent. let me know if any problems

while testing this i noticed a bug that undoing does not restore cursors that were merged. i will fix later

fixed.

RAV64 commented 1 month ago

https://github.com/user-attachments/assets/e697df28-b1a3-490d-8a28-a9d4d9aca49b

In this scenario, multicursors on the number 1 comment. deleting up with "dk" and undoing the cursors end up in wrong place.

https://github.com/user-attachments/assets/abfb055c-26cc-4b37-a3e2-eef109f0b440

If the cursors are on the number 2 and you delete up with "dk" and undo, the cursors end up on the number 1.

It seems like, when you delete upwards and undo, the cursors end up n rows too high where n is the "d{n}k". If you do "d2k" and undo, the cursors end up 2 rows too high.

jake-stewart commented 1 month ago

i'm not sure where the problem is.

try the same thing without multicursor and undo should behave the same. when undoing, you go to the start of the changed region.

unless i misunderstand your issue?

RAV64 commented 1 month ago

i'm not sure where the problem is.

try the same thing without multicursor and undo should behave the same. when undoing, you go to the start of the changed region.

unless i misunderstand your issue?

Oh - you're completely right. Thats strange it works like that 😅

RAV64 commented 1 month ago

https://github.com/user-attachments/assets/1ba88a26-12e1-48db-820d-cea64d96f1e5

Two cursors on same line and doing "dd" to delete that line deletes 2 lines. (Notice the "loop" line being deleted)

jake-stewart commented 1 month ago

i'm going to consider that expected behaviour. you have two cursors deleting a line and so two lines are deleted. can always do 0dd to merge the cursors first