-
-
Notifications
You must be signed in to change notification settings - Fork 2.5k
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
Better f
à la clever-f and vim-sneak like jump motion
#274
Comments
I think an issue with this is that it is not very discoverable. |
Ah, doom emacs seemed to have this as well. Why not? But doom emacs behavior is a bit different, if you do |
That's how it's also done in |
That's definitely a cool idea! |
Something like EasyMotion is one of the things that I would most like to see added to Helix, it's super convenient. |
The blocker for this is virtual text support, but @cessen had some concerns about the extensibility of the current rendering system to fit in virtual text #411 (comment). |
+1 for clever-f Especially: @Omnikar who already started working on this in #1162 A modal editor with built-in Sneak-like movements would be beyond awesome in itself; but I'd like to bring Lightspeed and especially Leap to your attention, that take a more sophisticated approach than either Sneak or EasyMotion, aiming for the lowest cognitive overhead. There are three separate ideas that could be implemented on top of Sneak:
These features can in fact be added independently, but the combination of all three provides the most fluid experience of course. This Leap-style navigation would take some more work, but it's not fundamentally more complex than vanilla Sneak - displaying labels, i.e., virtualtext support is the only thing that is necessary in the core. I'd love to help if there is interest in (parts of) this! |
I like using hop.nvim, and the hop line has replaced relative line numbers for me too. |
hop.nvim built-in 🔥 |
|
There is #3791 which is mostly just blocked on some extensions to the rendering system |
Nice! Happy to see that! |
I would also like to give my vote to a behviour like leap.nvim's. Out of all the "cursor jumping" plugins for Neovim that I've tried Leap's approach is the most clever one in my opinion. Like @ggandor mentions, a big advantage with Leap is that it gives you one unique virtual label already after your first keystroke. This gives you more time to process the key to press to get to where you want, resulting in a smoother experience with basically no interruption. You're already looking at the first and second key to press before even initiating the jump, and while you're typing the second character you're seeing the third character to type (if the two characters are unique you don't have to type a third). This is possible because you always type the character of the target and the real character after it. |
I wholeheartedly have to agree with @mawkler here. Leap's implementation, after testing pretty much every single jump plugin out there, was by far the most intuitive, efficient and thought through in my opinion. Reasons basically what @mawkler mentioned, and the readme of the repo he linked has great explanation as well. |
That’s what’s going to be a problem with motion plugins: people will always find a given plugin better and smarter, and there is no consensus. So #3791 is really ambitious to implement both worlds, that’s truly amazing. 🙂 |
What is the difference between hop.nvim and Lea.nvim? I don't really get that from the readme. #5340 seemed liked it worked Luke leap from looking at leaps readme |
@pascalkuthe Hop is in the EasyMotion family. It creates a hint everywhere on the screen and you press those hints. The strategy is configurable (the labels can be distributed by sorting them depending on the distance to the cursor, keep them always the same regarding the buffer screen, etc.). Kitty implements such a thing too. Leap / Lightspeed etc. are in the Sneak-based family. They are more opinionated and will distribute the labels in a different way. For instance, it works with two characters (Hop has lots of motions, like the 2-char, 1-char, pattern based, generalized via the API, etc.). It will start showing labels after you type the first character. It’s a matter of preference, but yes, you will find a bit of overlap. |
Thanks for this. So the difference seems to be that |
I’m not sure it’s easier, I think it’s similar, because once you have the logic to generate the combinations of labels and the logic to place them as virtual text, the algorithms should be pretty similar. In Hop, I have some short-circuit where I will jump to sole occurrences, etc. Sneak has a more dynamic way of presenting things (you type a character, it already highlights stuff, then you type a second one and it might jump on sole occurrence or ask you for a label), but ultimately, it’s similar — and Leap is actually a subset of Hop, since Hop is more general, we could have a « HopLeap » mode. In that regard, I agree that sticking to a single kind of movement is easier. Something that Hop users use probably the most is the concept of jumping to a word. It highlights all words and you jump to them directly. Most of the time, it’s faster than the 2-char, but if you think of worse complexity, then you might end up with 4 char to types (one to trigger Hop, and three characters to type). That last situation happens when you have a LOT of things on screen, and Hop does multi-window thing. It’s actually pretty hard to end up with three characters to type if your |
And invoking So yes, supporting everything Hop supports (or EasyMotion, really) is more work than Leap, but I don’t think Helix should support everything. It should probably support something like the « words » mode, and the dynamic 2-char from Leap. It should be enough, I guess? |
Would be great if the leap like behavior would also be implemented. So much more convenient to jump and the other one is just so distracting :) |
Showing the labels ahead of time complicates things significantly, I think in that case the feature should be designed with that in mind from the start.
if you forget about the pause between typing the trigger and the label, which is (mostly) eliminated by the "dynamic" 2-char mode
Neither is more general than the other, both can be fed with custom targets/patterns, as well as custom callbacks (to do something else instead of jumping). The difference is that Leap does not have built-in commands for word/etc-wise motions, because the philosophy is that it's better not having to think about the kind of motion itself, and if "dynamic" 2-char mode is always at least an 80% solution in terms of net speed (and often the best), plus it eliminates the friction (=pause), then it makes sense to rely on it all the time. As noted, this is an opinionated approach, no need to agree with it. |
#5340 actually already implements That does not detract from the usefulness of either approach. I think both approaches have merits and it's probably personal preference to some degree. It would be sweet to have both (with shared code where possible) and people can bind whatever command they want (the default would be what @archseer prefers as usual). |
Everyone is tossing around "Hop-like", "Sneak-like" etc., as if we'd be talking about some binary choice between two particular behaviors that can be summarized in one sentence, while in fact there is a vast design space for such a feature, with many different, often orthogonal aspects.
|
Yes, I 100% agree with that.
Hey! I didn’t know that! I find that peculiar, and defeats completely things like cross-window jumps (in Hop, every commands like Also,
I agree and disagree. That « pause » is just you reading the hint label. In Hop, most of the label are 1 or 2 characters long (I never really type 3 characters long in real world use cases), and as such, your brain read the whole thing at once. In Leap, you see them ahead of time but does it really matter? I.e. you still need to think about the next key you type before actually jumping. I mean, I agree that in theory AOT labelling seems superior, but in practice, not so sure. If we get both motions in Helix, I think it’s great and there’s really nothing to debate, as it’s a personal thing as mentioned above. To be honest, at first, I thought that Helix wouldn’t even implement any motion plugin (since it has relative line number) and because it’s such a niche world. I planned on implementing / using a Kitty kitten to do that (and I still consider it, because it allows to do the same thing with all my TUIs, not only Helix). |
@phaazon I've been using leap.nvim (or its predecessor lightspeed.nvim) for almost a year and I find that I basically always can get to where I want in 3 (or less) key presses. Far less than 1% of the time do I have to shift group. |
@mawkler It’s probably similar to Hop then (I never have to type more than 3 key presses — 1 to trigger a Hop motion, and two key label at max). I was just mentioning the fact that @ggandor said that if we have gazillions matches (which is unlikely but it can happen multi-window on really big documents), Hop will use 3-char, hence 4 characters, while that switch group thing from Leap will probably require more. |
Yeah, right. This is one example where we optimize for the common case, and not over-generalize. It's definitely easier to type 3 labels instead of pressing tab/space, say, 8 times, but similar to @mawkler's experience, on my laptop I don't remember ever having to switch to an actual invisible group in practice (when not stress-testing Leap on artificial examples), so even on a big screen it's probably a rare thing. (Remember, Leap labels 2*N matches right away.) On the other hand, the fact that "a label is always one character, period", is a very nice invariant to rely on. Not only results it in a bit less visual noise, but more importantly, the handling of conflicts becomes far easier (which is far from trivial even with 1-char labels in case of 2-char patterns and AOT labeling). It's not a clear win, I just explained the rationale. I've been toying with the idea of multi-char labels, but always rejected it for the above reasons.
There's a super-simple way of finding that out, try it in practice.
I just listed a bunch of things above illustrating why the phrase "both motions" (meaning "leap" and/or/vs "hop") makes absolutely no sense in this context, as they're not representing one particular feature or behavior, but a configuration based on multiple sets of (possibly interdependent) choices and approaches, so in any case, there are things to think through before rushing to implement this. Anyway, as a Neovim user at the moment I don't care too much about how much bloat Helix accumulates, but still. |
From the implementation side of view, I'd like to point out that #5340 already supports both hop and leap style behaviors. We can have further discussion on how to tackle the design space, but just wanted to point out that whichever direction we go, existing code should be in good shape in either direction. |
Since we're already deviating from the behavior of
f
in vim (multiline, not restricted to the current line), it'd we useful if we could go a step further and implement something like clever-f. It would enable pressingf
again immediately after a previousf
search (pressing any other key resets this) in lieu of;
. This is really useful when you get the count wrong forf
and want to spamf
to go to the desired match.Another really useful feature would be something along the lines of vim-easymotion and vim-sneak for jumping anywhere in the view (uses two letters to find the jump point).
The text was updated successfully, but these errors were encountered: