emacs-evil / evil

The extensible vi layer for Emacs.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Don't move cursor (and don't unhighlight) options in evil mode

sahlte opened this issue · comments

Issue type

  • Enhancement request

Environment

Emacs version: 29.3
Operating System: Ubuntu 22.04.3
Evil version: 1.15
Evil installation type: MELPA
Graphical/Terminal: Graphical
Tested in a make emacs session: Yes

Reproduction steps

  • Start Emacs
  • Have evil mode
  • Observe highlighting disappear when yanking region
  • Follow the below cursor examples

Expected behavior

Have the option to make evil-mode not mess with the highlighted region or cursor position when acting on a region.

Actual behavior

When you copy (y) or format (=) some text, evil will remove your highlighted region (if you are in a visual mode) and move your cursor. The cursor position will always be set to the original point or mark preferring the one which comes first. If you are in visual mode it will always unhighlight your region, which feels like it should be opt in/out.

##Cursor example:
If you highlight from left to right and yank, your cursor will jump to where you started highlighting.
If you highlight from right to left and yank, the cursor will stay where you stopped highlighting.
If you highlight top to bottom and yank, your cursor will jump to where you started highlighting.
If you highlight bottom to top and yank, the cursor will stay where you stopped highlighting.
This also applies to something like "y%" or "ya(". If you start on the "(" your cursor will be left there. If you started on the ")" your cursor will be moved to the "(".

As you can see, the point always ends up on whichever, mark or point, comes earlier in the buffer.
The cursor also moves sometimes when you "undo" some change, which is somewhat unexpected and the user should be able to turn it off.

##TLDR

  1. Users should be able to tell evil-mode to not unhighlight the region I act on.
  2. Users should be able to tell evil-mode to not move cursor after acting on a region.
  3. Users should be able to tell evil-mode to not move cursor after "undo".

Further notes

Here is the hacky solution I have in my config:

  (defun my/evil-dont-move-cursor-or-unhighlight-advice (orig-fun &rest args)
    "Stop evil mode from unhighlighting region or moving the cursor."
    (let ((orig-point (point))
	  (orig-mark (mark))
	  ;; note: calling (evil-visual-direction) actually doesn't give correct results so use the variable
	  (orig-direction evil-visual-direction))
      (apply orig-fun args)
      (if (eq evil-state 'visual)
	  (progn
	    (evil-visual-make-region (mark) (point))
	    (when (= orig-direction 1)
	      (exchange-point-and-mark)))
	(goto-char orig-point)
	(set-mark orig-mark))))

  (evil-define-operator my/evil-yank (beg end &optional type register yank-handler)
    "Basically applies the `my/evil-dont-move-cursor-or-unhighlight-advice` only to yank commands that were called directly. We don't want to advice the original evil-yank because it causes trouble with evil-visual-paste"
    :move-point nil
    :repeat nil
    (interactive "<R><x><y>")
    ;; Call the original evil-yank
    (my/evil-dont-move-cursor-or-unhighlight-advice 'evil-yank beg end type register yank-handler))

  (define-key evil-motion-state-map (kbd "y") nil)
  (define-key evil-normal-state-map (kbd "y") nil)
  (define-key evil-motion-state-map (kbd "y") 'my/evil-yank)

  (advice-add 'evil-indent :around #'my/evil-dont-move-cursor-or-unhighlight-advice)

I add advice around evil-indent because I find that it is hard to simply wrap this function like with evil-yank. I avoid wrapping evil-yank because it makes evil-visual-paste act wrong. I have not tried messing with undo.

Hi @sahlte thanks for the issue. As a rule of thumb, we'll only add features to evil which exist in vim or neovim, or which address an issue related to the interplay between emacs and evil. There are probably some exceptions to this, and if, for example, this issue got a deluge of upvotes in a short period of time, I'm sure we could make an exception.

However, to address each of your points:

  1. Bringing back the selection after it's unhighlighted is so quick and easy that I don't think hacks like your suggestion are really necessary. Simply hitting gv will restore the selection. For most users, being put back in normal mode is more often what you'd want than what you don't, and for the times when that's not the case, you're just two keypresses away from getting the selection back.
  2. Returning the cursor to where it was before acting on a region is also quick and easy with
`]

or

`>

(assuming the cursor was at the end of the region)
So again, I don't think it's enough of an inconvenience to add an option to change the default.
3. In vim, you can (I think always) get back to roughly where you were before an undo with

``

I admit that evil doesn't seem to emulate this very well, so I would be happy to consider this for improvement. But again, actually adding a setting to not move the cursor does seem unnecessary.

My hunch is that your requests are rare enough, and emacs is extensible enough, that your above solution is sufficient. It's always difficult to balance the addition of settings against a focus on keeping the codebase simple, but in this case I think I'd err in the latter direction.