20

In the 'normal' state of evil-mode, cursor movement is emulating the standard behavior of vim. I want to make it more similar to the standard emacs behavior in the following two ways.

  1. I want vertical movement to take place within visual lines, rather than logical lines. I.e. if a line is wrapped, pressing j or <down> should move to the next part of the same line.

  2. I want horizontal movement to not stop at newlines. I.e. if the cursor is at the end of a line, pressing l or <right> should move to the next line.

How can I achieve this?

kalj
  • 1,432
  • 2
  • 13
  • 30

5 Answers5

33

I found how to solve problem 2: It turned out there was a variable evil-cross-lines. Setting this to t simply solved that problem.


Together with the fix for vertical movement by PythonNut, here is the full solution:

;; Make movement keys work like they should
(define-key evil-normal-state-map (kbd "<remap> <evil-next-line>") 'evil-next-visual-line)
(define-key evil-normal-state-map (kbd "<remap> <evil-previous-line>") 'evil-previous-visual-line)
(define-key evil-motion-state-map (kbd "<remap> <evil-next-line>") 'evil-next-visual-line)
(define-key evil-motion-state-map (kbd "<remap> <evil-previous-line>") 'evil-previous-visual-line)
; Make horizontal movement cross lines                                    
(setq-default evil-cross-lines t)
kalj
  • 1,432
  • 2
  • 13
  • 30
5

The remap solution would make `dj' like combinations fail. Below advice solution still keeps right behavior for `dj':

(defun evil-next-line--check-visual-line-mode (orig-fun &rest args)
  (if visual-line-mode
      (apply 'evil-next-visual-line args)
    (apply orig-fun args)))

(advice-add 'evil-next-line :around 'evil-next-line--check-visual-line-mode)

(defun evil-previous-line--check-visual-line-mode (orig-fun &rest args)
  (if visual-line-mode
      (apply 'evil-previous-visual-line args)
    (apply orig-fun args)))

(advice-add 'evil-previous-line :around 'evil-previous-line--check-visual-line-mode)
xwl
  • 840
  • 10
  • 12
2

I can't seem to get right movement working. C-h k l says right-char.

;; kill two birds with one stone using remap: arrow keys and h,j,k,l
(define-key evil-normal-state-map (kbd "<remap> <evil-next-line>") 'evil-next-visual-line)
(define-key evil-motion-state-map (kbd "<remap> <evil-previous-line>") 'evil-previous-visual-line)
(define-key evil-motion-state-map (kbd "<remap> <evil-next-line>") 'evil-next-visual-line)
(define-key evil-normal-state-map (kbd "<remap> <evil-previous-line>") 'evil-previous-visual-line)
(define-key evil-normal-state-map (kbd "<remap> <evil-backward-char>") 'left-char)
(define-key evil-motion-state-map (kbd "<remap> <evil-forward-char>") 'right-char)
(define-key evil-normal-state-map (kbd "<remap> <evil-backward-char>") 'left-char)
(define-key evil-motion-state-map (kbd "<remap> <evil-forward-char>") 'right-char)
PythonNut
  • 6,182
  • 1
  • 25
  • 41
1

Readers in 2023:

Evil now has a configuration option for moving to the next visual line, set evil-respect-visual-line-mode to non-nil (must be done before Evil is loaded).

Remember you'll need to have visual-line-mode enabled for the Evil setting to work. Turn on visual-line-mode either per-buffer in whatever hooks (e.g. programming language modes) you use or globally via (global-visual-line-mode t) and you're set.

Direct link to documentation for this option: https://evil.readthedocs.io/en/latest/settings.html#elispobj-evil-respect-visual-line-mode

tsujp
  • 1,066
  • 1
  • 12
  • 29
  • This was working wonderfully on Emacs 27 on WSL for me. But after that I upgraded to emacs v28.2 and it stopped working. – CoredusK May 19 '23 at 09:25
  • Update: In doom emacs with emacs 27, it worked to put this variable in config.el, however when upgrading to emacs 28, the config has to be put in the init.el file, on top https://github.com/doomemacs/doomemacs/issues/401#issuecomment-588502773 – CoredusK May 19 '23 at 09:32
0

2) As for the second question (good point), I managed to do the following. I don't know how to tell evil not to stop at end/beginning of lines, but I know how to redefine some keys:

(define-key evil-normal-state-map "h" 'left-char) ;;remaps evil's h to emacs' left movement

left key:

(define-key evil-normal-state-map [left] 'left-char)

but doing the same with emacs' right-char doesn't work :/ I'm looking at it.

ps: to find the function associated to a key: C-h k <your key>

Ehvince
  • 17,274
  • 7
  • 58
  • 79