emacs-evil / evil

The extensible vi layer for Emacs.
GNU General Public License v3.0
3.39k stars 281 forks source link

Using logical lines for <num>j and <num>k #817

Closed zhiwei-nu closed 7 years ago

zhiwei-nu commented 7 years ago

I use evil-next-visual-line for normal navigations, but sometimes i do 5j to move up 5 lines, for example but it only counts visual lines.

In Vim, I can do this:

" Prevents us from moving irregularly for soft-wrapped lines
nnoremap <expr> j v:count ? 'j' : 'gj'
nnoremap <expr> k v:count ? 'k' : 'gk'

I have mapped the relevant keys as below:

  (define-key evil-motion-state-map "j" 'evil-next-line)
  (define-key evil-motion-state-map "k" 'evil-previous-line)
  (define-key evil-operator-state-map "j" 'evil-next-line)
  (define-key evil-operator-state-map "k" 'evil-previous-line)
  (define-key evil-normal-state-map "j" 'evil-next-visual-line)
  (define-key evil-normal-state-map "k" 'evil-previous-visual-line)

This works for operators (like d5j) but not for motions.

Is there any way to get this to work? Thanks in advance!

wasamasa commented 7 years ago

The mappings look somewhat bogus to me. Adding a binding for motion state and normal state doesn't make a difference unless you've customized a mode to start in motion state. Customizing operator state shouldn't be needed either.

The way to solve this is by writing your own command and binding it:

(evil-define-motion my-evil-next-line (count)
  (interactive "P")
  (let ((command (if count 'evil-next-line 'evil-next-visual-line)))
    (funcall command (prefix-numeric-value count))))

(define-key evil-motion-state-map (kbd "j") 'my-evil-next-line)

Writing the corresponding function for the other direction should be a piece of cake.

zhiwei-nu commented 7 years ago

@wasamasa i tried this, but it messes up other commands, so actions like d5j will have very different behavior

wasamasa commented 7 years ago

Works fine for me. You'll have to be more specific than "messes up other commands".

zhiwei-nu commented 7 years ago

@wasamasa Thanks for responding! So to elaborate, one issue is that when i do d<num>j, for example, it deletes from where my cursor is instead of the start of line:

image

with this config: image

It's worse when commenting out things: image

image

Would you happen to know what causes this?

wasamasa commented 7 years ago

Looks like it's only calling evil-next-visual-line for you which shouldn't be the case if only the proposed function is used. Perhaps you still have other bindings active from previous customization attempts? Please try reproducing with a minimal init file.

zhiwei-nu commented 7 years ago

You can take a look at the config, I've stripped down most things and still have the same issue.

zhiwei-nu commented 7 years ago

From what I observed, the command is correct, but it seems things go wrong when we call the function. Just to test it out i put (if count 'evil-next-line 'evil-next-line), and the result was the same.

wasamasa commented 7 years ago

Yeah, no, I won't debug Spacemacs for you. What I had in mind was something very close to emacs -Q, like what you get when running make emacs from inside a Git checkout of this repository.

zhiwei-nu commented 7 years ago

Solved. The fix was to put :type line, like so:

  (evil-define-motion my-evil-next-line (count)
    :type line
    (let ((command (if count 'evil-next-line 'evil-next-visual-line)))
      (funcall command (prefix-numeric-value count))))