Skip to content

Comments

Revert SpawnMultiCursor{Up,Down} honoring softwrap + overhaul LastVisualX usage#3503

Merged
dmaluka merged 4 commits intomicro-editor:masterfrom
dmaluka:spawcursorup-logical-lines
Oct 20, 2024
Merged

Revert SpawnMultiCursor{Up,Down} honoring softwrap + overhaul LastVisualX usage#3503
dmaluka merged 4 commits intomicro-editor:masterfrom
dmaluka:spawcursorup-logical-lines

Conversation

@dmaluka
Copy link
Collaborator

@dmaluka dmaluka commented Oct 13, 2024

In #3145, namely in 9f36c57, we changed the behavior of SpawnMultiCursor{Up,Down} to spawn cursor in the next visual line within a wrapped line when softwrap is enabled. That was done for "consistency" with cursor movements (Cursor{Up,Down} etc). However it seems there are no actual use cases for that. Whereas at least some users (see issue #3499) prefer to spawn cursor in the next logical line, regardless of the softwrap setting.

So restore the old behavior.

In the future we may also consider adding actions like CursorUpLogical, CursorDownLogical etc, for moving cursor by logical lines even if softwrap is enabled, if there are users that want it. For now let's just fix multicursor spawning.

...That is just a part of the story. Simply reverting 9f36c57 is not enough, since it would make SpawnMultiCursor{Up,Down} broken, due to another change from #3145, namely 93b5326, due to the fact that LastVisualX currently assumes visual lines, not logical lines, so mixing logical lines usage with LastVisualX usage would cause SpawnMultiCursor{Up,Down} spawn cursors at unexpected locations in some cases.

The easy way would be to revert 93b5326 as well, but that means bringing back the issues fixed by 93b5326, which would be unfortunate.

So instead rework LastVisualX and GetVisualX() usage: restore the original semantics of LastVisualX that it used to have long ago, before #2076: last visual x cursor location in a logical line, not in a visual line. And add a separate LastWrappedVisualX field for last visual x cursor location in a visual line. So we can track last x position at the same time for both cases when we care about softwrap (e.g. cursor movements) and when we don't care about it (e.g. for spawning multicursors, in order to fix #3499, and possibly in the future for Cursor{Up,Down}Logical etc).

Also this fixes a minor bug: in InsertTab(), when tabstospaces is enabled and we insert a tab, the amount of inserted spaces depends on the visual line wrapping (i.e. on the window width), which is probably not a good idea.

Fixes #3499

Since we already have the StoreVisualX() helper, use it all over the
place instead of setting LastVisualX directly.

This will allow us to add more logic to StoreVisualX() add let this
extra logic apply everywhere automatically.
Restore the original meaning of LastVisualX before commit 6d13710
("Implement moving cursor up/down within a wrapped line"): last visual x
location of the cursor in a logical line in the buffer, not in a visual
line on the screen (in other words, taking tabs and wide characters into
account, but not taking softwrap into account). And add a separate
LastWrappedVisualX field, similar to LastVisualX but taking softwrap
into account as well.

This allows tracking last x position at the same time for both cases
when we care about softwrap and when we don't care about it. This can be
useful, for example, for implementing cursor up/down movement actions
that always move by logical lines, not by visual lines, even if softwrap
is enabled (in addition to our default CursorUp and CursorDown actions
that move by visual lines).

Also this fixes a minor bug: in InsertTab(), when `tabstospaces` is
enabled and we insert a tab, the amount of inserted spaces depends on
the visual line wrapping (i.e. on the window width), which is probably
not a good idea.
In cursor's Goto(), which is currently only used by undo and redo, we
restore remembered LastVisualX and LastWrappedVisualX values. But if
the window had been resized in the meantime, the LastWrappedVisualX
may not be valid anymore. So it may cause the cursor moving to
unexpected locations.

So for simplicity just reset these values on undo or redo, instead of
using remembered ones.
Commit 9fdea82 ("Fix various issues with
`SpawnMultiCursor{Up,Down}`") changed SpawnMultiCursorUp/Down actions to
honor softwrap, i.e. spawn cursor in the next visual line within a
wrapped line, which may not be the next logical line in a buffer. That
was done for "consistency" with cursor movement actions CursorUp/Down
etc. But it seems there are no actual use cases for that, whereas at
least some users prefer spawning multicursor in the next logical line
regardless of the softwrap setting. So restore the old behavior.

Fixes micro-editor#3499
@dmaluka dmaluka force-pushed the spawcursorup-logical-lines branch from c23ebe8 to e6ed161 Compare October 13, 2024 23:42
Copy link
Member

@JoeKar JoeKar left a comment

Choose a reason for hiding this comment

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

@dmaluka
Copy link
Collaborator Author

dmaluka commented Oct 15, 2024

By intention: the next commit 6214abb changes those 2 places to set c.LastVisualX instead of c.LastWrappedVisualX. In those 2 places we don't need to update c.LastVisualX, since c.LastVisualX, unlike c.LastWrappedVisualX, doesn't depend on the window width or on whether softwrap is enabled.

Hmm... it just occurred to me that it means that in those 2 places, i.e. when we resize the window or enable/disable softwrap, we "reset" cursor up/down movements if softwrap is enabled (i.e. when LastWrappedVisualX is used) but don't "reset" them anymore if softwrap is disabled (i.e. if LastVisualX is used). So it introduces a small "inconsistency" here. OTOH, perhaps this inconsistency is a rather good thing: this "resetting" of cursor up/down movements is generally an undesirable thing to do, we do it out of necessity and for simplicity, so since we indeed can avoid doing it as least if softwrap is disabled (and we achieve that for free, just as a side effect of this PR), it's a good thing?

@JoeKar
Copy link
Member

JoeKar commented Oct 15, 2024

By intention: the next commit 6214abb changes those 2 places to set c.LastVisualX instead of c.LastWrappedVisualX.

Ah, I see. Was interrupted for a long time right after the review of the first commit and thus didn't realize that.

this "resetting" of cursor up/down movements is generally an undesirable thing to do, we do it out of necessity and for simplicity, so since we indeed can avoid doing it as least if softwrap is disabled [...], it's a good thing?

Is it worth documenting this there, just for faster realization?
Besides that it should be right.

@dmaluka
Copy link
Collaborator Author

dmaluka commented Oct 15, 2024

Is it worth documenting this there, just for faster realization?

At the moment I'm inclined to think it's better to leave this without documenting, this is of too little importance to draw attention to it with a comment in the code (perhaps no real user will ever pay attention to this subtle difference in behavior), and if we ever need to think about this again, it shouldn't be difficult to figure out from the code what's going on.

@JoeKar
Copy link
Member

JoeKar commented Oct 16, 2024

Ok, does work so far as intended and SpawnMultiCursorUpN() does the job.
I tried it with MouseMultiCursor too, but this does respect the visual lines only and doesn't care about softwrap. Now I'm undecided if this fits into the picture.

PS:
Why exactly was it named SpawnMultiCursorUpN() instead of SpawnMultiCursorDirection(N)()?

@dmaluka
Copy link
Collaborator Author

dmaluka commented Oct 16, 2024

Why exactly was it named SpawnMultiCursorUpN()

Just because we also have UpN().

I tried it with MouseMultiCursor too, but this does respect the visual lines only and doesn't care about softwrap. Now I'm undecided if this fits into the picture.

What does MouseMultiCursor have to do with this?

@JoeKar
Copy link
Member

JoeKar commented Oct 16, 2024

Just because we also have UpN().

I understand, just because of the consistency. Well, then we go again with this ugly name.

What does MouseMultiCursor have to do with this?

It spawns multiple cursors by clicks and does this in soft-wrapped visual lines too, which is what we prevent, when we do it with the keyboard only in the same scenario. For me it's inconsistent, but maybe I don't get it again...as so often.

@dmaluka
Copy link
Collaborator Author

dmaluka commented Oct 16, 2024

I understand, just because of the consistency. Well, then we go again with this ugly name.

I don't find it particularly ugly. It is "move N lines up", where N may be negative.

It spawns multiple cursors by clicks and does this in soft-wrapped visual lines too, which is what we prevent, when we do it with the keyboard only in the same scenario.

We don't prevent spawning multicursors in soft-wrapped visual lines (why would we?), we just prevent spawning multicursors in the same logical line, when using SpawnMultiCursorUp and SpawnMultiCursorDown.

In other words, we just ensure that in cases like the following:

image

when the cursor is on the slash after github.com, SpawnMultiCursorDown will spawn a cursor on the slash after github.com in the next line, not on the character in the current line that is visually below the slash (the first f letter in buffer in this case).

@JoeKar
Copy link
Member

JoeKar commented Oct 20, 2024

we just prevent spawning multicursors in the same logical line, when using SpawnMultiCursorUp and SpawnMultiCursorDown.

Ok, then just for the completeness what I was referring to...

Without this PR with SpawnMultiCursorUp and MouseMultiCursor:
Bildschirmfoto vom 2024-10-20 14-36-58
Bildschirmfoto vom 2024-10-20 14-37-06

With this PR with SpawnMultiCursorUp and MouseMultiCursor:
Bildschirmfoto vom 2024-10-20 14-37-38
Bildschirmfoto vom 2024-10-20 14-37-46

I would expect to adapt the behavior of MouseMultiCursor to the one of SpawnMultiCursorUp resp. SpawnMultiCursorDown and don't create a cursor on the first o of bool.
But in case this isn't the common sense, we can add it as is too. Maybe I search analogy where non is and non shall be.

@dmaluka
Copy link
Collaborator Author

dmaluka commented Oct 20, 2024

MouseMultiCursor just spawns a cursor wherever you click with the mouse, without any relation of to the previous cursor's position, right? So what does MouseMultiCursor have to do with anything here?

@JoeKar
Copy link
Member

JoeKar commented Oct 20, 2024

MouseMultiCursor just spawns a cursor wherever you click with the mouse, without any relation of to the previous cursor's position, right?

Hm, yes. I was more thinking about the block-selection scenario (with the mouse), which MouseMultiCursor doesn't realize.
In a real block-/row-selection scenario selected with the mouse we should have the same behavior, but not in this random selection case.

So what does MouseMultiCursor have to do with anything here?

You're right, nothing. Forget about it.

@dmaluka dmaluka merged commit f293f98 into micro-editor:master Oct 20, 2024
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.

regression: SpawnMultiCursorUpN function

2 participants