-
Notifications
You must be signed in to change notification settings - Fork 270
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Vimode: fix cursor position after using undo #1328
Conversation
Seems to make sense, just curious when the problem exactly happens - could you give an example when the output of the plugin differs from vim? |
Sure, here's an example: Open a 5 line file With a real VIM, the cursor stays on line 2 |
But this isn't really what vim does, is it? Try the following with this patch:
The undo happens but your cursor is still on the first line instead of being at the position of the change which is very confusing. I think what you want instead is to get the information where the undo happened and move the cursor to the first line of the diff. Maybe you could achieve this using |
You're right, my previous correction was not correct. 327cdde is a new fix using the SC_MOD_BEFOREINSERT and SC_PERFORMED_UNDO events to save the cursor position. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me apart from the few formal comments above and the possible goto_nonempty()
use. Would you incorporate those changes into this PR?
vimode/src/cmds/edit.c
Outdated
@@ -162,14 +163,14 @@ void cmd_del_word_left(CmdContext *c, CmdParams *p) | |||
void cmd_undo(CmdContext *c, CmdParams *p) | |||
{ | |||
gint i; | |||
gint pos = SSM(p->sci, SCI_GETCURRENTPOS, 0, 0); | |||
start_undo(c); | |||
for (i = 0; i < p->num; i++) | |||
{ | |||
if (!SSM(p->sci, SCI_CANUNDO, 0, 0)) | |||
break; | |||
SSM(p->sci, SCI_UNDO, 0, 0); | |||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't goto_nonempty()
be used here to go to the first non-white character on a line? vim seems to behave this way, even though in a bit inconsistent manner - when you perform dd
, undo goes to the first non-white character while when you use 2dd
, it goes where the cursor was before.
If goto_nonempty()
is used, it should only be run when some actual undo happened and also when the cursor is at the beginning of a line so it doesn't jump somewhere else when you e.g. delete a word in the middle of a sentence.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, I made these changes and I am now using goto_nonempty()
2b99b71.
That's right, this is probably the simplest way to approach VIM's behavior.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, what I had in mind was something like (beware, totally untested!!!):
void cmd_undo(CmdContext *c, CmdParams *p)
{
gboolean undo_performed = FALSE;
gint pos;
gint i;
undo_start(c);
for (i = 0; i < p->num; i++)
{
if (!SSM(p->sci, SCI_CANUNDO, 0, 0))
break;
SSM(p->sci, SCI_UNDO, 0, 0);
undo_performed = TRUE; // <--- this is added
}
undo_end(c);
// the code below is added
pos = SSM(ctx->sci, SCI_GETCURRENTPOS, 0, 0);
if (undo_performed && is_start_of_line(p->sci, pos))
goto_nonempty(p->sci, pos, FALSE);
}
without the need to pass anything extra in the context. Am I missing something? Since I didn't run or even compile it, it's quite possible.
excmd_undo()
could just call this function then.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, I tried to refactor the code 63b7e25.
But excmd_undo
cannot simply call cmd_undo
because of the use of CmdParams
parameter.
So I moved this code into a new undo_apply
function which is called by cmd_undo
and excmd_undo
.
vimode/src/cmds/undo.h
Outdated
|
||
#include "context.h" | ||
|
||
void start_undo(CmdContext *c); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd prefer the names to start with undo_
, so e.g. undo_start()
here.
vimode/src/cmds/undo.c
Outdated
c->undo_pos = pos; | ||
} | ||
|
||
gboolean end_undo(CmdContext *c) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the gboolean return value used for anything?
vimode/src/cmds/undo.c
Outdated
{ | ||
ScintillaObject *sci = c->sci; | ||
|
||
if (c->undo_pos != -1) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
{ on a separate line to match the style of the rest of the code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also two empty lines between functions in the file if possible.
vimode/src/cmds/undo.h
Outdated
@@ -0,0 +1,28 @@ | |||
/* | |||
* Copyright 2024 Jiri Techet <[email protected]> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Like above.
vimode/src/cmds/undo.h
Outdated
|
||
void start_undo(CmdContext *c); | ||
void update_undo(CmdContext *c, gint pos); | ||
gboolean end_undo(CmdContext *c); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
void instead of gboolean?
vimode/src/cmds/edit.c
Outdated
@@ -162,14 +163,14 @@ void cmd_del_word_left(CmdContext *c, CmdParams *p) | |||
void cmd_undo(CmdContext *c, CmdParams *p) | |||
{ | |||
gint i; | |||
gint pos = SSM(p->sci, SCI_GETCURRENTPOS, 0, 0); | |||
start_undo(c); | |||
for (i = 0; i < p->num; i++) | |||
{ | |||
if (!SSM(p->sci, SCI_CANUNDO, 0, 0)) | |||
break; | |||
SSM(p->sci, SCI_UNDO, 0, 0); | |||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, what I had in mind was something like (beware, totally untested!!!):
void cmd_undo(CmdContext *c, CmdParams *p)
{
gboolean undo_performed = FALSE;
gint pos;
gint i;
undo_start(c);
for (i = 0; i < p->num; i++)
{
if (!SSM(p->sci, SCI_CANUNDO, 0, 0))
break;
SSM(p->sci, SCI_UNDO, 0, 0);
undo_performed = TRUE; // <--- this is added
}
undo_end(c);
// the code below is added
pos = SSM(ctx->sci, SCI_GETCURRENTPOS, 0, 0);
if (undo_performed && is_start_of_line(p->sci, pos))
goto_nonempty(p->sci, pos, FALSE);
}
without the need to pass anything extra in the context. Am I missing something? Since I didn't run or even compile it, it's quite possible.
excmd_undo()
could just call this function then.
Looks good, thanks! One last request - would you squash all the commits into one? I'll merge it afterwards. |
Also prefix the commit message with |
63b7e25
to
cc7d25d
Compare
OK, I did it, is it okay? |
Looks great, thanks! |
Trying to get more Vim-like behavior for cursor position after using undo (U key)