noctuid / lispyville

lispy + evil = lispyville
GNU General Public License v3.0
313 stars 23 forks source link

lispy-mark-symbol in normal state marks extra char past symbol unless lispyville-enter-special-when-marking is used #19

Closed bpstahlman closed 7 years ago

bpstahlman commented 7 years ago

When I'm not using lispyville-enter-special-when-marking and lispy-mark-symbol is executed from normal state, an extra char past the end of the symbol is pulled in to the region. I've verified that lispy-mark-symbol is calculating the correct bounds to pass to lispy--mark, which in turn passes the correct bounds to set-mark, so I'm assuming the problem lies in some sort of region activation hook.

noctuid commented 7 years ago

This is the same problem I mentioned earlier. The bounds are actually wrong for evil because of how it behaves with the point at the region-end (it includes the character on/after the point in the region). You can see this if you try running evil-visual-char with the bounds given by lispy--bounds-dwim. So it's not a good idea to just bind lispy marking commands directly in normal state; I need to alter them first. Thanks for reporting, I'll fix this when I get the chance.

bpstahlman commented 7 years ago

Understood. Sorry, I wouldn't have submitted a bug if I'd realized the final update yesterday wasn't intended to fix...

On Wed, Jan 18, 2017 at 12:54 PM, Fox Kiester notifications@github.com wrote:

This is the same problem I mentioned earlier. The bounds are actually wrong for evil because of how it behaves with the point at the region-end (it includes the character on/after the point in the region). You can see this if you try running evil-visual-char with the bounds given by lispy--bounds-dwim. So it's not a good idea to just bind lispy marking commands directly in normal state; I need to alter them first. Thanks for reporting, I'll fix this when I get the chance.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/noctuid/lispyville/issues/19#issuecomment-273566046, or mute the thread https://github.com/notifications/unsubscribe-auth/AC7pQBM3gsmb_LHDMtk1DjsBKSDmsiiFks5rTl_rgaJpZM4Lm4x2 .

noctuid commented 7 years ago

Well the readme made it sound like mark key theme was meant to be used withlispyville-enter-special-when-marking, but really, it should work either way. It should be working now.

I also found a seemingly unsolvable bug in lispyville-enter-special-when-marking and am considering removing it altogether (lispyville-wrap-command used with special would be the suggested alternative).

bpstahlman commented 7 years ago

On the subject of lispyville-enter-special-when-marking... I've been using it in conjunction with mark-toggle, and there's something that surprises/confuses me. My initial thinking was that hitting v once would put me in lispy special. Then, if I wanted to operate on something in visual state, I could simply hit v again; alternatively, I could stay in lispy special till I was done, then hit ESC to cancel the region and return to normal state. What surprises me is that, although the initial v does indeed put me in lispy-special, it also leaves me in visual state - sort of...

More specifically, lispyville--enter-special calls (evil-change-state lispyville-preferred-lispy-state) to put me in insert state, and all of the lispy keybindings are active. (I haven't delved deeply into evil yet, but I'm assuming the keymap switch happens in an evil state transition hook - correct?) On the other hand... evil-state is now "visual" and (evil-visual-state-p) returns t. The result is that the subsequent (i.e., the second) v (which I'd meant to take me back to visual state), results in a call to (lispyville--state-transition t) within lispyville-toggle-mark-type, and this effectively puts me all the way in lispy-special: i.e., evil-state is now "insert" and (evil-visual-state-p) returns nil. At this point, hitting v a third time gets me back to where I expected to be on the second press: i.e., non-special visual state, with lispy keybindings deactivated.

Is this by design, or does it have something to do with the insoluble problem you mentioned?

noctuid commented 7 years ago

Yeah, that's exactly the bug I was talking about. Switching to insert or emacs state works fine normally, but if it's done in evil-visual-state-entry-hook, it doesn't work properly like you point out. I looked at when the entry hook is run, and it seems to be run after everything else happens, so it's not immediately clear what the cause is. I'll have to look at evil's code more to see if I can find the reason for this (I don't know if I'll be able to find it).

I tried advising around evil-visual-state, but it ended up being disastrous (making emacs unusable). Even if I got that working, I'd rather not do something so drastic. I have a few ideas for workarounds, but if this ends up causing other problems, I may just remove the functionality. You can achieve the same thing just by wrapping a few commands with (lispyville-wrap-comand <name> special). In that case, I'd add a mark-special key theme as well.

bpstahlman commented 7 years ago

Perhaps when the hook is called, everything but the setting of evil-state to "visual" has been done. In that case, the call to (evil-insert-state) in the hook would set evil-state to "insert", only to have it set back to "visual" after the hook function had returned.

At any rate, why not put the transition to special before the call to lispy-mark-symbol (instead of in the visual state entry hook)? E.g., something like this...

(defun mark-symbol-and-enter-special ()
  (interactive)
  (evil-change-state lispyville-preferred-lispy-state)
  (lispy-mark-symbol))

When I run this command from normal mode, I get...

Now if I hit v, I get...

noctuid commented 7 years ago

It looks like the problem may be that there is a (let ((evil-state 'visual)) ...) around the (run-hooks...). It may be intentional to prevent any of the code inside that let from changing evil-state. It seems strange to me because there is already a (setq evil-state 'visual) before.

I guess the nice thing about having it in the hook is that you don't need to modify any commands. I don't think the order matters if it's not running from the hook; binding v to (lispyville-wrap-command lispy-mark-symbol special) should work fine as well. I added a mark-special key theme and updated the readme to no longer recommend using lispyville-enter-special-when-marking.

bpstahlman commented 7 years ago

I've played around with it a bit. I definitely like both mark-special and mark-toggle. But I've found what looks like a "one-off" bug pertaining to marking the final symbol in a list. To reproduce...

(foo bar baz)

With point on foo or bar in normal state, v works as expected. But try putting point on baz in normal state and hit v.Although baz is highlighted, the parens surrounding the list are also highlighted, and point is after the closing paren, as though Lispy thinks it has marked the entire list, rather than just its final element. At this point, j, k and other commands acting on the region behave in unexpected ways, as though Lispy isn't quite sure what sort of region it's dealing with... Pretty sure the problem is caused by an "off by one" issue involving the end of the region: If I add a single space between baz and the closing paren, the issue goes away.

noctuid commented 7 years ago

My bad, the issue was actually my fault. lispyville-wrap-command is actually supposed to put the point into special if there isn't an active region as well. The logic I had was messed up, so it was attempting to put the point in special as if there was no region in this case (by moving past the paren). It should be fixed now.

bpstahlman commented 7 years ago

That seems to have fixed it. Thanks!

bpstahlman commented 7 years ago

Incidentally, I couldn't help but notice that your config had something that looked rather spacemacs-ish. Also, noticed you're the author of the General package. I'm a long-time Vim user who wants efficient editing on top of a lisp machine. I shied away from Spacemacs initially - though in some respects, it seemed tailor-made for someone like me - because I was afraid it would hide too much of Emacs from me. But now I'm not so sure. It's not that I can't remember or execute Control/Meta key chords: it's just that the inherent inefficiency and awkwardness of the paradigm galls me. I've toyed with the idea of using god-mode, but I've noticed that it doesn't appear to work well with lispy (which I guess isn't surprising, given that lispy implements its own sort of "god mode"). Any thoughts/recommendations you might have on any of this would be greatly appreciated. I'm guessing you've been down this same path some time ago...

noctuid commented 7 years ago

One of the main reasons I started using emacs is because I like vim so much. To me, knowing emacs' default keybindings is not important. I still only know the basic ones and have always used evil completely. One of the great things about emacs is how accommodating it is to other editing styles and keybinding systems. I disagree with the recommendation that people (especially those coming from vim) start out using vanilla emacs to "learn" emacs. Learning about builtin functionality/commands can be very useful, but I don't feel that learning/using the default keybindings is in any way fundamental in doing that. Chords are more efficient in some cases, but chords can still be used in conjunction with modality, and vim-style modality has a lot of advantages that are acknowledged even in many popular non-evil packages. For me, efficiency is the most important consideration, and I think that evil, while not perfect, serves as the best base for efficient text editing (in general at least). I'm very biased about this and feel that evil is the best fit for me, but I won't say that god-mode or some other modal package isn't a better solution for some people's needs.

As for spacemacs, I'm not a user. While it looks very polished, has great discoverability, and has lots of functionality by default, it is lacking when it comes to efficiency (e.g. very long key sequences for common commands). I'm very picky and like to have everything configured exactly as I want it. I'm sure plenty of people have had success building a heavily personalized configuration on top of spacemacs, but to me, it would just get in the way.

That all said, I'd recommend trying spacemacs, god-mode, etc. if you are unsure. In the end, a lot of the emacs packages that make editing more efficient can be used effectively regardless of the editing style.

bpstahlman commented 7 years ago

I believe I've been coming to this same conclusion for some time now. While god-mode can mitigate the pain of Control/Meta chords, Vim's built-in modes obviate the need for the mitigation. And for me, avoiding an issue altogether is always preferable to coming up with mitigations, no matter how clever. (Incidentally, I find a certain surreal absurdity in the oft-repeated claim that the Emacs paradigm is better because it prevents your having to remember whether you're in normal or insert mode... The notion that someone who has trouble remembering whether he's in normal or insert mode could be even remotely productive in standard Emacs is nothing short of preposterous... ;-)

I've also considered using the composable.el package, but while it does provide "orthogonality" of operators/motions/objects, the absence of modes means you're still stuck with Emacsey keystrokes for the operators themselves (as well as some of the motions): e.g.,

D vs C-w C-e

I have to admit, though, that composable.el provides some very clever tricks for repeating commands, marking objects, and determining whether commands operate from point to beginning or end of the object. I'm not prepared to dismiss it without some additional investigation/experimentation, but my initial impression is that the behavior is a bit less regular and intuitive than evil's, and you're still limited to a set of motions that is decidedly less complete than evil's (e.g., no f, F, t, T, etc...) (Now being able to use it in conjunction with something like avy might be a game-changer.) On the other hand, there's still the cognitive burden of developing/maintaining 2 distinct sets of finger memory for the same thing: e.g., I'll continue to use Vi-style mappings in less pagers and such, and will be much more likely to have access to Vi/Vim than Emacs on some of the remote systems I occasionally use. Adopting your customization approach might make me fairly dependent upon my ".emacs". (Then again, I already consider my ".vimrc" to be pretty much a prerequisite on any machine I'll be using for any non-negligible amount of time.) I suppose the advantage of a canned solution here is that installation can be accomplished quickly and easily on pretty much any strange system without a thumb drive, even one that's connected only to a local network (provided it has access to a standard linux package repo).

One perhaps less obvious advantage to the customization approach is that (unless I'm much mistaken) it would force me to understand Emacs at a deeper level (e.g., major/minor modes, keymaps, etc...) than would Spacemacs or an alternative solution that simply provides a more convenient interface to the default keybindings. (I've probably learned more about Emacs while tinkering with Lispy/Lispyville over the past few weeks than in all my previous (aborted) attempts to make the switch over the past decade or two...) If my experience thus far is any indication, even a well-designed solution like Spacemacs won't shield me completely from major/minor mode conflicts, especially as I start using more and more packages. And if I'm going to have to invest some time in getting a useful package working, I might as well take the time required to get it working in a way that's optimal, not merely usable...

I really appreciate the suggestions and rationale you've provided. It's been most helpful...

noctuid commented 7 years ago

Vim-style modality offers benefits that can be replicated without it like composability, but even with composability, you are restricted to chords (for the most part) to initiate commands as you point out. Vim's separation of inputting text and "editing" text is not efficient when you only want to take a single action (like moving up/down a line and continuing to input text). However, as soon as multiple editing actions start taking place in a row, the cost (the keys needed for switching modes) is paid for, and you start saving keystrokes. That is the main reason I like using modality in most places. For some applications, there is even lest of a cost to modality (e.g. browsing; you already can't input text unless in a text box). Hydra operates on a similar principle (more convenient keybindings for repeated actions), but it's not on a global level like evil. It's more comparable to vim-submode (though much better).

Since you bring up avy and f, F, etc., I'll mention evil-easymotion which can be used to create evil motions that use avy. Also, I can't recommend using it at this point as I need to add more tests and fix a lot of basic issues it has, but I'm also working package that can create "remote" versions of text objects that are selected with avy (see targets.el). Support for "remote" text objects is implemented locally but has not yet been committed.

As for remote systems or systems where I don't have access to emacs, I luckily don't often have to use them. I've used shfs in the past, and many people say they use TRAMP with great success. If those solutions aren't viable for you, but you can have a .vimrc you're familiar with, I'd recommend going with that approach.

Yes, I've personally found that tinkering with emacs has been very helpful in learning more about it.

bpstahlman commented 7 years ago

Targets.el looks very promising. I'll keep an eye on it... I'd heard of evil-easymotion, but hadn't really looked into it much before now. Looks very powerful. Hydra is something I was vaguely familiar with, but having just perused its readme, I'm now thinking it could be very useful even with an almost pure evil approach. I guess the bottom line is that the elegance and power of some of these approaches is too much to forgo on a day to day basis, even if I can't be assured of access to it all on every computer I'll ever use. Given that I do the vast majority of my computing on just a couple of computers, settling for a "lowest common denominator" configuration would really be letting the tail wag the dog...