Issue #109 open

Make paren highlighting consistent with evil-move-cursor-back

dnquark
created an issue

The paren highlighting behavior is different in insert and normal states: in normal state, it occurs when the cursor is on the closing paren, and in insert/emacs states it occurs when the cursor is right after the closing paren, as is standard Emacs behavior.

When evil-move-cursor-back is set to t, this makes sense since the highlighting of a parentheses pair persists through the state change. However, when one sets {{{ (setq evil-move-cursor-back nil) }}} (e.g. to get familiar Emacs behavior when cursor is at the end of line) this leads to inconsistent paren highlighting / conflicting visual feedback as one switches between insert and normal modes. For instance, the backward/forward-sexp commands should take one from the opening to the closing (and vice versa) highlighted paren regardless of the mode.

Comments (9)

  1. Frank Fischer repo owner
    • changed status to open

    Even with evil-move-cursor-back to nil the current vim-like behavior makes sense, for example in contrast to Emacs commands the command '%' works with the closing parenthesis at point, not before point, and this is independent from evil-move-cursor-back. In fact, this was one of the main reasons why the highlighting has been implemented as it is now. The issue with forward/backward-sexp is true, of course, but depends on whether you ever need these function (I never use them, not even in emacs-lisp programming). We could add a list of states which should do vim-like highlighting, if that would help (you could set this list to nil). But note that then also the additional highlight range via evil-show-paren-range would not work anymore (but even this could be customized, if required).

  2. dnquark reporter

    The reason I have avoided using '%', and the reason I like evil-move-cursor-back set to nil is the behavior of selection with respect to the last character. For some reason, I often select things from right to left. However, by default, in normal mode, something like $v^ "loses" the last character of a line, or if I'm trying to select (foo) with the point on ) by doing v%, I similarly lose the last character of what I'm trying to select. This is annoying and inconsistent with the Emacs behavior I'm used to.

    I think this is actually the main issue here. The paren highlghting behavior is consistent with the '%' command, but the command itself suffers from the at point/after point dichotomy between Emacs and Vim.

    I don't know if there are other commands that suffer from this, but it would certainly be nice to provide versions conforming to Emacs behavior. In this case, it would mean changing evil-jump-item so that it operates on a closing paren before point. (A corner case like (foo)|(bar) could be considered separately.) This has the benefit that the paren highlighting then could be identical in insert and normal states.

    Another possible solution would simply be to ensure that the last character is always selected (although as an Emacs user, I'd prefer a solution that conforms to Emacs behavior :) ).

    In general, the issue of inclusive/exclusive selection needs some attention: there is evil-visual-char variable, but its behavior needs more refinement. One might expect that setting it to 'inclusive might help ensure the selection of the last character, however, this setting is only a partial fix and introduces other problems:

    • it still doesn't help with selecting (foo|) using v%
    • copying whole line via $v^ works with 'y' (evil-yank), but doesn't work (last character still lost) with 'M-w' (kill-ring-save) (probably a bug)
    • it gets in the way of visually selecting several lines: consider
    |foo
    bar
    baz
    

    -- here, if we do vjj, we end up selecting

    foo
    bar
    b
    

    (whereas the intent was to select two lines, without the linebreak.

  3. Frank Fischer repo owner
    • changed status to open
    However, by default, in normal mode, something like $v^ "loses" the last character of a line, or if I'm trying to select (foo) with the point on ) by doing v%, I similarly lose the last character of what I'm trying to select.
    

    I do not understand this. Normal visual state is inclusive, i.e., the character under point is included in the visual selection. Thus v% while point is on the closing parenthesis should include the complete text "(foo)". Similarly ^v$ should include all characters in the line including the last one (but excluding the newline character at the end of the line, of course). At least this is the default configuration of both Vim (afaik) and Evil. Perhaps you changed your configuration?

    I aggree that there are some difference between "usual" Vim and usual Emacs behavior. Most Emacs motions interpret regions half-open (or exclusive) while many Vim motions interpet them inclusive. For example forward-word places point on the first character after the end of the next word whereas the closest corresponding Vim motion "e" places point on the last character of the next word. Probably similar things hold for other motions.

    Evil in its default configuration tries to be as close to Vim as possible. But I agree that it may be nice to preserve as much Emacs behavior as possible for some users. Perhaps a lot of this can already be achieved by some redefinitions of key-bindings (e.g., bind "e" to forward-word to stay with the example above) and a few configuration options. In order to get a consistent behavior, we should specify first what a more-Emacs-like behavior should be from the users' pointer of view (I have no idea because I'm more sticky to Vim-like behavior;)). Then we could think of what's necessary to get there. Perhaps it's as easy as

    1. change some key-bindings to Emacs motions
    2. undefine those overriding key-bindings in insert-state
    3. set visual state to exclusive instead of inclusive
    4. set evil-move-cursor-back to nil
    5. change the matching-parenthesis highlighting
    6. ...

    Most of this may already be possible without too much effort.

    Your last example: yes, that's inclusive visual state behavior of Vim. For selecting lines you should use linewise visual state "V", not character-wise visual state. But this is really a difference between both.

    Reading your comment again ... did you try your examples with make emacs in evil's source? I really wonder if the problems you describe come from some specific setting of configuration options (even your "M-w" example works for me, of course not including the final newline, so I'm a little confused).

  4. dnquark reporter

    Ah, for a monent I forgot that evil-visual-char 'inclusive was in fact the default, and was further confused by a somewhat strange bug that causes kill-ring-save to misbehave with Evil (I reported it as issue 110) -- so it was, in fact, configuration-specific.

    In terms of what constitutes Emacs-like behavior: it's not an easy question to answer in full generality. It might be easier to come up with examples where Vim and Emacs behavior diverge, and evaluate the options for bridging the two. There are two main cases: (1) user executes Emacs commands in insert or normal state and gets results that are different than what they would get in the Emacs state and (2) user executes Vim's equivalents of Emacs commands, but gets different results. In both cases, it's worth considering implementing options that would yield the expected Emacs results.

    My examples are of both varieties. The fact that the point moves back in the normal state breaks backward-sexp (this is the "type 1" example). This is, in part, fixed by setting evil-move-cursor-back to nil. (The remaining issues are then inconsistent highlighting of parens, as described above, and the fact that "%" becomes less convenient to use. In principle, both these issues can be fixed, although if there aren't other commands that would benefit from this, it might be a low priority optimization.) The "type 2" example is the difference between "regular" and "linewise" visual states (incidentally, I feel a bit silly for not knowing about the latter). It is natural for an Emacs user to conceptualize "v" and "C-SPC" as being the same operation. Thus, it is very unexpected when vjj produces results different from <C-SPC><C-n><C-n>. It would be a good idea to have an option to change that (so I officially submitted the feature request as Issue 111 :) ).

    For me personally, if Issue 111 is implemented, I would start using evil-visual-char 'inclusive and not worry for the time being about backward-sexp being broken in normal state. Then we could wait for feedback of other "native Emacs speakers" to see if other Emacs vs Vim behavior differences emerge that merit addressing.

  5. Frank Fischer repo owner

    Add `evil-highlight-closing-paren-at-point-states' customization variable

    This variable lists the states in which the adaption of `show-paren-mode', which highlights the closing parenthesis *at* point instead of before point, should be active. If this list contains the symbol 'not then its meaning is inverted. This addresses issue #109.

    Wiki macro error: Changeset e2d2df2fc8a9 not found.

  6. Log in to comment