How to move between visual lines and move past newline in evil-mode

6.9k views Asked by At

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?

5

There are 5 answers

0
kalj On BEST ANSWER

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)
1
Ehvince On

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>

2
PythonNut On

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)
2
tsujp On

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

0
xwl On

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)