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

Make M go to middle line of window #1136

Open
lobre opened this issue Sep 26, 2023 · 20 comments
Open

Make M go to middle line of window #1136

lobre opened this issue Sep 26, 2023 · 20 comments

Comments

@lobre
Copy link

lobre commented Sep 26, 2023

Hello,

I know that M does Restore selections from mark. But it replaces in my opinion an important motion of vim which is to go to the middle line of window.

						*M*
M			To Middle line of window, on the first non-blank
			character |linewise|.  See also 'startofline' option.

I find it weird that vis has L, H but not M. It is not really consistent in my opinion.

Also, in the docs (:help) in the OPERATOR-PENDING section, it is still written:

  M                 	Move cursor to middle line of the window

So it seems the doc has not been updated in this section. Or otherwise, it is that I don't understand what M means in the context of "operator-pending".

I don't have a better replacement for restore selections from mark at the moment. And I understand that it resonates with m being attributed to marks globally in vim. But I still it is worth exploring if something better could be found.

@rnpnr
Copy link
Collaborator

rnpnr commented Sep 26, 2023

That looks like an ancient bug. I believe it should be gM which
is inline with :

  gm                	Move cursor to middle of screen/display line

Does that make more sense?

@lobre
Copy link
Author

lobre commented Sep 26, 2023

For me, it seems gM means yet another thing in vim. gm and gM are for horizontal moves. The former goes to the column considered as the center of the screen, while the latter is for the center of the line.

gm

Like g0 but half a screenwidth to the right. 

gM

Like g0 but to halfway the text of the line.

I don't know if gM is currently implemented this way in vis, but if that is the case, it means it cannot be used for moving the cursor vertically to the middle line.

@rnpnr
Copy link
Collaborator

rnpnr commented Sep 26, 2023

Based on that it seems that gm in vis is similar to what gM in
vim does. The behaviour of gm in vim makes no sense for vis; we
do not and will not support horizontal scrolling viewports so going
half a screen over is useless.

To me gM - [g]oto [M]iddle of view makes the most sense to me given
what gm does. I think it should be fixed that way and a section
can potentially be added to the "Differences from Vi(m)" wiki page.

@lobre
Copy link
Author

lobre commented Sep 27, 2023

I did not realize that gM was not implemented and that horizontal scrolling did not exist in vis 🥳.

So gM is actually free.

Do you think it makes more sense to have gM doing goto Middle of view vertically and M doing Restore selections from mark or the opposite?

@lobre
Copy link
Author

lobre commented Sep 27, 2023

To me having L, M and H consistent for moving around makes sense.

Also not exactly related, but I feel weird that we have g_ for Move cursor to last non-blank character of the line, but we are missing _ which in vim moves the cursor to the first non-blank character.

In vis, it is Remove leading and trailing white space from selections.

I know vis does not have to be fully compliant with vim, but for "matching/related" motions such as those quoted here, I find the behaviour in vis rather inconsistent not only with vim, but also by nature.

@rnpnr
Copy link
Collaborator

rnpnr commented Sep 27, 2023

I can see the argument for using M that way since that is what
M does in traditional vi and vim. However I'm not sure internal
consistency of vis' more powerful features should be dropped in
favour of consistency with vi/vim. I would be interested in hearing
what other people think.

we have g_ but we are missing _

It seems like g_ was probably added for compatibility. We have
^ to go to the first non blank. I would be against changing _
since that has been around for most of the life of vis and I use
it a lot. I'm sure its the same with other long term vis users.

@lobre
Copy link
Author

lobre commented Sep 28, 2023

I am also interested in hearing more about other people's opinions on the topic. I personally think that the basic editing features should be as consistent as possible with vim, and that vis should add up those extra features around multi-cursors and sam expressions.

This is an ideal statement of course, and in practice, there are use cases with clashes where decisions should be taken. What makes vim popular is the style of editing. So for me, this has to be strongly applied in vis so that people are directly familiar. And then, they can learn about those superpowers that vis brings, while staying a minimalist and well-scoped editor.

Otherwise, I just want to mention that in vim, ^ and _ are not exactly identical, and the same for $ and g_.

Let me start with the latter.

Both $ and g_ go To the last non-blank character of the line and [count - 1] lines downward |inclusive|.

However, the small difference is for visual mode. No changes for g_, but for $, In Visual mode the cursor goes to just after the last character in the line.. So the end-of-line character is caught.

So if you want to visually select until the end of the line without catching the end-of-line, you should use g_.

Now for ^ and _, the main difference is that _ takes a count. So if I do 2_, I will be on the first non-blank character of the line just below (1_ is the same as _). And so this is for example useful at the end of a macro if you want to execute it multiple times and apply it on successive lines.

All those differences seem subtle but for an old accustomed vim user, they are burnt in memory and if they are not the same in vis, they will be painful to revert mentally. Vim is an established language and changing the language is a risky bet in my opinion. And this is what differentiates vis with kakoune for example (which decided to create its own brand new language).

I also have comments about how text-object motions are executed in vis when the cursor is outside matching objects. But the topic is a bit different so I think I will create another issue to keep them focused.

@lobre
Copy link
Author

lobre commented Sep 29, 2023

I would be against changing _ since that has been around for most of the life of vis and I use it a lot.

I would also rebound on this. While I can totally understand your statement, maybe it is important to bring some history and design choices of vim about _.

Disclaimer, I feel like vis took inspiration from Kakoune for _, as in this editor, it also unselect whitespace surrounding each selection. I love using _ in Kakoune and feel that it simplifies a lot the intent. Selections, motions and text objects can be implemented in a purely "dumb way". They do what the user expects. Doing alt+i ( will select everything in the parenthesis, no matter if there are newlines, whitespace or anything. Same, doing x will select the full line, from column 0 to the last columns including the new line. Then, it is up to the user to use _ to strip the selection to the bare minimum. Combining those is like playing a game. I can easily manipulate selections.

If I want to select all lines within those brackets:

my_var = [
  "first",
  "second",
  "last"
];

I can first select inside the brackets with alt+i [, then I strip to the pure content with _, and I choose to go back to line mode with x. It composes really well.

Vis inherits more from vim's design. And in vim, _ is a way to "refer to the current line".

See this comment: https://github.com/neovim/neovim/blob/af7d317f3ff31d5ac5d8724b5057a422e1451b54/src/nvim/normal.c#L5865

/// "_" is a strange motion command that helps make operators more logical.
/// It is actually implemented, but not documented in the real Vi.  This motion
/// command actually refers to "the current line".  Commands like "dd" and "yy"
/// are really an alternate form of "d_" and "y_".  It does accept a count, so
/// "d3_" works to delete 3 lines.

See also this thread which explains why _ is the initial bit that led to "linewise" motions: https://vi.stackexchange.com/a/19746.

Many people say that d3_ makes more sense compared to 3dd when knowing that _ refers to the "current line". It composes better.

So I think vis should either decide to follow vim with this model and implement all the "linewise" behaviors, or drop it and make it clear why in the docs (but this is dropping well-established vim workflow). And of course, if those do not exist, we should make sure that what they do can be replaced by something else in vis. In this occasion, g_ alone also loses its meaning, so if you don't want _, you'd better drop g_ as well.

@ninewise
Copy link
Collaborator

ninewise commented Sep 30, 2023 via email

@lobre
Copy link
Author

lobre commented Sep 30, 2023

I'd prefer to have something for 'go to previous non-blank character' as a more basic motion

I am not sure to follow you here. Isn't that B?

Otherwise, vis is inspired by vim. It does not have to follow it precisely, but to me it is a really hard task to draw the line about what to include and what not. If you include too few, people will always ask for the addition of xxx feature which is missing. And you will never have a concrete reason about not including except: this is my personal feeling as a maintainer (or user of vis). And of course you are biased regarding which vim features you were using frequently vs which you did not use.

All the vim emulation modes out there in editors or in vim clones are living the same story. They are lacking feature either because they decided so, or because they have technical reasons that prevent them from implementing the feature correctly. And this makes a poor vim experience and people end up retiring from using the tool.

I think that choices should be driven by concrete reason, and not about feelings. Of course we can disagree here, and including just whatever you feel like including is a strategy. But regarding the future longevity of this piece of software, I think it is precarious.

Vim is clearly lacking a precise specification about its editing mode (not talking about other features of vim outside of edition such as arglist, quickfix, tabs, mappings, api, vimscript or other bits). But to me, it feels to be a better strategy to stay as close as possible to vim, and exclude features if there are clashing, or judged to be mistakes that we want to correct. But in either cases, this should be solidly argued and documented, so that it does not emanate from feelings.

Neovim did that, but also did a lot more and it's codebase has grown up a lot, making it less and less lightweight and focused. Vis in comparison has got good grounds and a solid design on paper.

@ninewise
Copy link
Collaborator

ninewise commented Oct 10, 2023 via email

@rnpnr
Copy link
Collaborator

rnpnr commented Oct 11, 2023

Perhaps we should work on a configuration on the wiki which would add (most) vim bindings we're missing via aliases and some lua functions?

Sounds like a good solution to me with the caveat that any mapping that changes a core vis binding needs to be clearly indicated.

I think I should apply the 2 line patch making gM go to the middle line of the window. Its a core motion but the default binding is very hard to use. Without mapping it to another binding I'm only able to get it working by manually setting the mode to OPERATOR_PENDING via lua and then pressing M.

@lobre
Copy link
Author

lobre commented Oct 11, 2023

Without mapping it to another binding I'm only able to get it working by manually setting the mode to OPERATOR_PENDING via lua and then pressing M.

This is also what I saw in the doc, but I was not sure how I was supposed to go into OPERATOR_PENDING. And I am not sure why this is implemented this way. Like "why is M mapped to go to the middle line in OPERATOR_PENDING?".

@rnpnr
Copy link
Collaborator

rnpnr commented Oct 11, 2023

It a side effect of how the keybindings are defined. See here:

vis/config.def.h

Lines 315 to 316 in aa18162

/* For each mode we list a all key bindings, if a key is bound in more than
* one array the first definition is used and further ones are ignored. */

It just happens that M is already assigned as something else in all modes besides OPERATOR_PENDING

@lobre
Copy link
Author

lobre commented Oct 11, 2023

Makes sense.

If we choose gM for the middle line, should we change L and H to gL and gH to stay consistent?

@lobre
Copy link
Author

lobre commented Oct 11, 2023

I am reading vis' documentation again and maybe there is something that I don't understand, but here is the part of the doc that explains marks:

m sets a mark, M restores it. For example, 'am sets the mark a while 'aM restores it.

It seems it works the opposite way of vim. In vim, you set a mark at a with ma. If I understand correctly, in vis you set a mark at a with 'am instead.

(by the way, if you have an explanation of why it is inverted, I am curious ^^).

So those m and M should be prefixed by the name of the mark anyway with 'a.

Hence, can we say that M is restore mark when there is a "pending" mark typed before? And if that is not the case, M is just go to the middle line?

@rnpnr
Copy link
Collaborator

rnpnr commented Oct 11, 2023

It seems it works the opposite way of vim. In vim, you set a mark at a with ma. If I understand correctly, in vis you set a mark at a with 'am instead.

(by the way, if you have an explanation of why it is inverted, I am curious ^^).

Yes that is by design. Marks are kind of like addresses for interactive modes. Once set they can also be used as addresses in commands (but that might have some limitations).

Hence, can we say that M is restore mark when there is a "pending" mark typed before? And if that is not the case, M is just go to the middle line?

No because there is an implicit default mark ('') when none have been specified. For me this would be the most common use (you set a mark with m, then go read/edit some other part of the file, then jump back with M).

@lobre
Copy link
Author

lobre commented Oct 12, 2023

No because there is an implicit default mark ('') when none have been specified. For me this would be the most common use (you set a mark with m, then go read/edit some other part of the file, then jump back with M).

Understood.

@mcepl
Copy link
Contributor

mcepl commented Dec 2, 2023

So, what remains here as an actionable issue? Or should this be closed?

@lobre
Copy link
Author

lobre commented Dec 4, 2023

Nothing has been done or acted upon since the beginning of this issue. So in that regard, I don't see how it could be closed. Possible changes that could be implemented here are actionable the the sense of being small and relatively easy. But we don't have a clear consensus and questions are yet to be answered.

Here is a summary.

  1. proposition of using M to go to the middle line of the window

It has been commented that M to mean "restore marks" is considered as being more important. gM has been proposed instead to go the middle line, but no patch was applied.

I then asked this question:

If we choose gM for the middle line, should we change L and H to gL and gH to stay consistent?

I am not particularly content about doing this, but still, the question was not answered.

I understand that vis does not aim for vim compatibility and I respect this, but not having M does mean it also breaks the POSIX spec. All the vi/vim clones I know about have H, L and M defined as in the POSIX spec.

But again, I was just trying to make a proposition for consistency and because it "makes sense to me". But I am no maintainer here and I respect the choice of maintainers if they want to go in a separate direction.

  1. _ does not have the POSIX/vim behavior and is not consistent with g_

Kind of the same thing, nothing has been decided. And it is pretty much the same story. This is basic POSIX vi behavior that is not present in vis. _ is for linewise motions. g_ is here, but no _. Many people rely on _ and not on ^ to go to the beginning of the line as this character is sometimes better located on non-English keyboards.

To remove the inconsistency, there was this proposition.

Not sure why we'd have g_. I'd prefer to have something for 'go to previous non-blank character' as a more basic motion, and leave people free to bind g_ to that if they want or use $<previous-non-blank> with whatever we pick for it. Especially if you also have a next-non-blank, so ^ could be a combination of basic motions, too.

I don't know what should be the last decision on those two ideas. I leave people running the project decide about the outcome. And according to what has been decided and after having clearly explained why, I am not against closing this.

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

No branches or pull requests

4 participants