Skip to content
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

Merged
merged 1 commit into from
May 22, 2024

Conversation

scresto09
Copy link
Contributor

Trying to get more Vim-like behavior for cursor position after using undo (U key)

@techee
Copy link
Member

techee commented Apr 25, 2024

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?

@scresto09
Copy link
Contributor Author

Sure, here's an example:

Open a 5 line file
Move the cursor to line 2
press "2dd" to delete 2 lines
press "u" to cancel

With a real VIM, the cursor stays on line 2
With Geany Vimode not patched, the cursor goes to the last line

@techee
Copy link
Member

techee commented May 8, 2024

But this isn't really what vim does, is it? Try the following with this patch:

  1. Delete a line in the middle of a file.
  2. Scroll to the top of the file so you have the cursor e.g. on the first line
  3. Press u

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 SC_PERFORMED_UNDO (not sure, I haven't studied how exactly this works and if it provides enough information).

@scresto09
Copy link
Contributor Author

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.

Copy link
Member

@techee techee left a 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?

@@ -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);
}
Copy link
Member

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.

Copy link
Contributor Author

@scresto09 scresto09 May 17, 2024

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.

Copy link
Member

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.

Copy link
Contributor Author

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.c Outdated Show resolved Hide resolved

#include "context.h"

void start_undo(CmdContext *c);
Copy link
Member

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.

c->undo_pos = pos;
}

gboolean end_undo(CmdContext *c)
Copy link
Member

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?

{
ScintillaObject *sci = c->sci;

if (c->undo_pos != -1) {
Copy link
Member

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.

Copy link
Member

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.

@@ -0,0 +1,28 @@
/*
* Copyright 2024 Jiri Techet <[email protected]>
Copy link
Member

Choose a reason for hiding this comment

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

Like above.


void start_undo(CmdContext *c);
void update_undo(CmdContext *c, gint pos);
gboolean end_undo(CmdContext *c);
Copy link
Member

Choose a reason for hiding this comment

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

void instead of gboolean?

@@ -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);
}
Copy link
Member

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.

vimode/src/utils.c Outdated Show resolved Hide resolved
vimode/src/utils.c Outdated Show resolved Hide resolved
@techee
Copy link
Member

techee commented May 21, 2024

Looks good, thanks!

One last request - would you squash all the commits into one? I'll merge it afterwards.

@techee
Copy link
Member

techee commented May 21, 2024

Also prefix the commit message with vimode: so it's clear what plugin the commit modifies.

@scresto09 scresto09 force-pushed the vimode-fix-undo-pos branch from 63b7e25 to cc7d25d Compare May 22, 2024 08:52
@scresto09
Copy link
Contributor Author

OK, I did it, is it okay?
Thanks

@techee techee merged commit 0e299a8 into geany:master May 22, 2024
2 checks passed
@techee
Copy link
Member

techee commented May 22, 2024

Looks great, thanks!

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

Successfully merging this pull request may close these issues.

2 participants