tommcdo / vim-exchange

Easy text exchange operator for Vim
MIT License
756 stars 23 forks source link

When swapping text from a lower line to a higher line, the cursor should stay at the higher line rather than jumping back #16

Closed svermeulen closed 9 years ago

svermeulen commented 10 years ago
one
two (cxx)
three
four
five

Then:

one
two
three
four (cxx)
five

Result:

one
four (cursor is here)
three
two (I would expect the cursor to be here)
five
tommcdo commented 10 years ago

I agree. The reason for the current behaviour is that the region later in the buffer is always changed first so that it doesn't affect the line and column position of the other region, and the exchange is performed using normal commands (so the cursor is actually being moved).

I was trying to maintain the cursor position when I first implemented that behaviour of exchange (later region first), but it was getting in the way of achieving the functionality, so I wrote it off as "acceptable" for the time being. But I try to will get back to that issue soon :)

svermeulen commented 10 years ago

Works great! Cheers.

tommcdo commented 10 years ago

Ah, I knew this fix seemed too simple. I forgot to test it on exchanges within the same line. If you exchange two regions of different length on the same line, the cursor will go back to beginning of where the second region used to be. It's a bit disorienting; I think it should probably go to the beginning of the region that replaced the original one. What do you think?

svermeulen commented 10 years ago

Yeah I see the issue as well. Couldn't you just offset the mark positions it by however many chars were added/removed from the first swap? Having it behave consistent with other cases would be pretty nice

tommcdo commented 10 years ago

It gets worse when you consider exchanging regions from all different modes, including combinations of modes.

There are many cases that require adjusting the cursor position with an offset. A column offset is the difference between the lengths of the first and second regions; a line offset is the difference between the heights of the first and second regions.

Below are the cases I've explored so far:

I haven't begun exploring the requirements for regions from different modes. I'll give it more thought later... hopefully some of the cases merge into each other :)

svermeulen commented 10 years ago

If you use marks instead of setpos / getpos the second issue would disappear since vim would apply the offset for you (but of course then you have to clobber a mark). Or actually a better option might be to always replace the text that is on a higher line first - that way there is no offset necessary for replacing the text on a lower line.

Blockwise exchange would definitely be tricky though, but personally I care less about that anyway

tommcdo commented 10 years ago

I don't want to use up marks if there's another way around it. I have no problem with the use of marks if they can be captured and restored before the user has a chance to notice, but in this case, the mark would have to be in use from the time they set the first region until the time they set the second region. I just have to figure out the cases and adjustments. It's a bit of work but I feel it's a nicer solution overall.

And as you stated, the use of marks wouldn't solve the problem for blockwise exchanges. Even though all but the most trivial blockwise exchanges are beyond human comprehension, I feel it's necessary to support them fully. The plugin should do exactly what the manual use of y and p would do.