¿Las mejores prácticas del modo malvado? [cerrado]

104

He estado usando Vim como mi editor principal durante años y probé Emacs varias veces durante ese tiempo. Luego descubrí Evil y decidí que satisface mi demanda de movimiento rápido lo suficientemente bien como para poder finalmente pasar a Emacs.

Entonces, para todos los usuarios de Evil, ¿cómo lo integran con las funciones normales de Emacs? ¿Ha encontrado algún conflicto entre este modo y otros? ¿Cuáles son sus experiencias / consejos dignos de compartir sobre este tema?

Daniel Duan
fuente

Respuestas:

71

Usé un vim altamente personalizado y ahora uso un emacs aún más personalizado. Creo que encontrará cada instancia de keymapping en mi archivo de configuración de keymapping https://github.com/mbriggs/.emacs.d-oldv2/blob/master/init/init-keymaps.el

Tenga en cuenta que estoy volviendo a unir cosas que los usuarios reales de emacs considerarían herejía, así que YMMV si alguna vez quiere aprender emacs "reales" (realmente no lo hago).

Una cosa que recomendaría a cualquier ex vimmer es esto

;;; esc quits
(defun minibuffer-keyboard-quit ()
  "Abort recursive edit.
In Delete Selection mode, if the mark is active, just deactivate it;
then it takes a second \\[keyboard-quit] to abort the minibuffer."
  (interactive)
  (if (and delete-selection-mode transient-mark-mode mark-active)
      (setq deactivate-mark  t)
    (when (get-buffer "*Completions*") (delete-windows-on "*Completions*"))
    (abort-recursive-edit)))
(define-key evil-normal-state-map [escape] 'keyboard-quit)
(define-key evil-visual-state-map [escape] 'keyboard-quit)
(define-key minibuffer-local-map [escape] 'minibuffer-keyboard-quit)
(define-key minibuffer-local-ns-map [escape] 'minibuffer-keyboard-quit)
(define-key minibuffer-local-completion-map [escape] 'minibuffer-keyboard-quit)
(define-key minibuffer-local-must-match-map [escape] 'minibuffer-keyboard-quit)
(define-key minibuffer-local-isearch-map [escape] 'minibuffer-keyboard-quit)

de modo que esc realmente cierra prácticamente cualquier cosa (como indicaciones pendientes en el minibúfer)

Matt Briggs
fuente
7
La definición de minibuffer-keyboard-quit se puede encontrar aquí: github.com/davvil/.emacs.d/blob/master/init.el
Adam Bell
1
@Adam lo siento por eso>.> Tengo un montón de cosas instaladas, a veces uso una función que creo que está incorporada, pero en realidad viene de otro lugar
Matt Briggs
3
Encuentro que esto no funciona para mí. Utilizo el último Emacs 24.4, ¿alguien experimenta lo mismo?
Dzung Nguyen
1
El vínculo está roto. Creo que este es el nuevo: github.com/mbriggs/.emacs.d/blob/master/config/keybinds.el
Sean Leather
1
@SeanLeather Respuesta actualizada a un enlace de trabajo.
Christopher Bottoms
34

Como alguien que vino de emacs, probó vim y se dio cuenta de que había una gran cantidad de cosas que ganar, experimenté mucho cuando comencé a usar el mal. Si bien lo siguiente es controvertido, quería mantener las claves de emacs que se usan de manera más universal en terminal, firefox, cocoa, etc., pero no quería perder las capacidades de edición de vim. Terminé decidiendo volver a enlazar las siguientes claves en mi .emacs:

(define-key evil-normal-state-map "\C-e" 'evil-end-of-line)
(define-key evil-insert-state-map "\C-e" 'end-of-line)
(define-key evil-visual-state-map "\C-e" 'evil-end-of-line)
(define-key evil-motion-state-map "\C-e" 'evil-end-of-line)
(define-key evil-normal-state-map "\C-f" 'evil-forward-char)
(define-key evil-insert-state-map "\C-f" 'evil-forward-char)
(define-key evil-insert-state-map "\C-f" 'evil-forward-char)
(define-key evil-normal-state-map "\C-b" 'evil-backward-char)
(define-key evil-insert-state-map "\C-b" 'evil-backward-char)
(define-key evil-visual-state-map "\C-b" 'evil-backward-char)
(define-key evil-normal-state-map "\C-d" 'evil-delete-char)
(define-key evil-insert-state-map "\C-d" 'evil-delete-char)
(define-key evil-visual-state-map "\C-d" 'evil-delete-char)
(define-key evil-normal-state-map "\C-n" 'evil-next-line)
(define-key evil-insert-state-map "\C-n" 'evil-next-line)
(define-key evil-visual-state-map "\C-n" 'evil-next-line)
(define-key evil-normal-state-map "\C-p" 'evil-previous-line)
(define-key evil-insert-state-map "\C-p" 'evil-previous-line)
(define-key evil-visual-state-map "\C-p" 'evil-previous-line)
(define-key evil-normal-state-map "\C-w" 'evil-delete)
(define-key evil-insert-state-map "\C-w" 'evil-delete)
(define-key evil-visual-state-map "\C-w" 'evil-delete)
(define-key evil-normal-state-map "\C-y" 'yank)
(define-key evil-insert-state-map "\C-y" 'yank)
(define-key evil-visual-state-map "\C-y" 'yank)
(define-key evil-normal-state-map "\C-k" 'kill-line)
(define-key evil-insert-state-map "\C-k" 'kill-line)
(define-key evil-visual-state-map "\C-k" 'kill-line)
(define-key evil-normal-state-map "Q" 'call-last-kbd-macro)
(define-key evil-visual-state-map "Q" 'call-last-kbd-macro)
(define-key evil-normal-state-map (kbd "TAB") 'evil-undefine)

(defun evil-undefine ()
 (interactive)
 (let (evil-mode-map-alist)
   (call-interactively (key-binding (this-command-keys)))))

Desafortunadamente, estos se superponen con las operaciones de vim "mover una pantalla hacia arriba o hacia abajo". Sin embargo, me he sentido cómodo usando lo siguiente en su lugar:

(define-key evil-normal-state-map (kbd "DEL") (lambda ()
                    (interactive)
                    (previous-line 10)
                    (evil-scroll-line-up 10)
                    ))

(define-key evil-normal-state-map (kbd "=") (lambda ()
                      (interactive)
                      (next-line 10)
                      (evil-scroll-line-down 10)
                      ))

Además, si viene de vim y desea una ruta rápida desde la inserción al modo normal usando "jk" (o cualquier otra combinación de 2 trazos), la mejor manera es copiar el texto de http://www.emacswiki.org/ emacs / download / key-chord.el y péguelo en su ~ / .emacs.d / key-chord.el. Luego agregue lo siguiente a su .emacs:

;load a file named key-chord.el from some directory in the load-path (e.g. "~/.emacs.d")
(require 'key-chord)
(key-chord-mode 1)
(key-chord-define-global "jk" 'evil-normal-state)

Además, si viene de vim y cree que la copia al portapapeles en emacs no es buena, probablemente tenga razón. Sin embargo, puede resultarle útil lo siguiente después de ejecutar sudo apt-get install xsel:

(defun copy-to-clipboard ()
  (interactive)
  (if (display-graphic-p)
      (progn
        (message "Yanked region to x-clipboard!")
        (call-interactively 'clipboard-kill-ring-save)
        )
    (if (region-active-p)
        (progn
          (shell-command-on-region (region-beginning) (region-end) "xsel -i -b")
          (message "Yanked region to clipboard!")
          (deactivate-mark))
      (message "No region active; can't yank to clipboard!")))
  )

(evil-define-command paste-from-clipboard()
  (if (display-graphic-p)
      (progn
        (clipboard-yank)
        (message "graphics active")
        )
    (insert (shell-command-to-string "xsel -o -b"))
    )
  )

(global-set-key [f8] 'copy-to-clipboard)
(global-set-key [f9] 'paste-from-clipboard)

Obviamente, tendrás que decidir por ti mismo si alguno de estos controvertidos cambios vale la pena, pero quizás estos cambios básicos te inspiren.

Para algunas otras implementaciones de funciones realmente interesantes, como eliminar y pegar, eliminar sin copiar al portapapeles, movimiento eficiente 4x / 16x, uso de recuentos para la especificación de registro de pegado, configuraciones de pestañas que realmente funcionan para c / c ++, y más, puede verificar los .emacs completos, init.el, my-keymaps.el y my-functions.el versons en mi git en https://github.com/Russell91/emacs

RussellStewart
fuente
2
todo esto es genial, agregué algunos en wikemacs: wikemacs.org/index.php/Evil#Configuration
Ehvince
Entiendo su voluntad de reutilizar sus hábitos de emacs. Para trabajar en Firefox, recomiendo encarecidamente probar el complemento Vimperator, que aporta muchas funciones similares a vim a su navegación. Sin embargo, utiliza comandos de movimiento vim de forma predeterminada (como es el caso de lesscommand y otros).
Jan Vlcinsky
Igual que a ti, no me gusta el enlace maligno en modo insert-state, así que simplemente vuelvo a enlazar "i" en el mapa de estado normal a 'evil-emacs-state.
user49117
En lugar de anular el teclado evil, lo elimino, por lo que vuelve a la configuración del teclado de emacs normales, por ejemplo(dolist (m (list evil-normal-state-map evil-motion-state-map evil-insert-state-map)) (define-key m "\C-e" 'nil))
Bach Lien
30

También solía ser un usuario de Viper / Vimpulse, con una gran cantidad de configuración. Entonces encontré el modo Evil.

¿Cuáles son sus experiencias / consejos dignos de compartir sobre este tema?

Esta es toda mi configuración de modo maligno, y funciona muy bien para mí:

(require 'evil)
(evil-mode 1)

;; Remap org-mode meta keys for convenience
(mapcar (lambda (state)
    (evil-declare-key state org-mode-map
      (kbd "M-l") 'org-metaright
      (kbd "M-h") 'org-metaleft
      (kbd "M-k") 'org-metaup
      (kbd "M-j") 'org-metadown
      (kbd "M-L") 'org-shiftmetaright
      (kbd "M-H") 'org-shiftmetaleft
      (kbd "M-K") 'org-shiftmetaup
      (kbd "M-J") 'org-shiftmetadown))
  '(normal insert))

¿Ha encontrado algún conflicto entre este modo y otros?

No, a diferencia de Viper / Vimpulse, que estaba causando problemas en varios modos.

Kenny Meyer
fuente
Recibo este error: progn: el valor del símbolo como variable es vacío: estado ¿Dónde se define el estado?
justingordon
Puedes intentarloevil-emacs-state
Kenny Meyer
2
¿Puede aclarar dónde puso eso?
justingordon
1
Esto es fantástico, busqué exactamente esto. ¡Upvotes en abundancia!
jplindstrom
1
Echa un vistazo a este github.com/edwtjo/evil-org-mode
avendael
17

Empecé a usar Evil hace un mes; antes, intenté usar viper / vimpulse sin mucho éxito. Para ser honesto, vimpulse es bastante bueno, pero usarlo con varios modos fue un poco problemático (por ejemplo, el modo de compilación donde vimpulse siempre se volvía loco) dejando a emacs en algún modo entre vi-emacs-algo.

Cuando cambié a Evil, finalmente comencé a explorar todo el poder de Emacs, y créanme, no me arrepiento. Evil funciona muy bien en todos los modos que utilicé (principalmente edición, compilación, scratch y eshell) e incluso leer info / man / help funciona sin problemas.

Excepto que, solo encontré el cambio de búfer extraño como solía hacer: b <0-9> en su lugar: b-TAB-then-complete-name o: bn. Sin embargo, tenga en cuenta que los desarrolladores de Evil intentan (en algunos casos) reducir las funcionalidades duplicadas, así que en su lugar:! (al comando de shell ejecutivo), debe usar M-! nativo.

Si siente la necesidad de agregar / redefinir algunos comandos ex personalizados, simplemente abra evil-maps.el y edítelo (¡pruébelo en vim!).

Evil es todavía un proyecto joven pero prometedor y estoy esperando el día en que reemplace a viper en la distribución oficial de Emacs.

Dennis
fuente
4
¿Se supone que esto implica que no es posible agregar / redefinir comandos en vim?
John Tyree
1
@JohnTyree Los comandos definidos por el usuario deben comenzar con una letra mayúscula en Vim, mientras que todos los comandos integrados comienzan con una letra minúscula.
Austin Taylor
10

Me gusta guardar el búfer cuando salgo del insert-mode: (editado: no pida guardar cuando no hay un archivo asociado para este búfer, como cuando estoy en un scratch o en un búfer magit)

(defun my-save ()
  (if (buffer-file-name)
    (evil-save))
)

   (add-hook 'evil-insert-state-exit-hook 'my-save)

para más posibilidades: consulte http://wikemacs.org/index.php/Evil

¡Comentarios bienvenidos para mejoras!

Ehvince
fuente
Gracias. Por cierto, tu enlace está roto.
Amos
Gracias también. Wikemacs volverá. El sitio está en mantenimiento, con suerte no por mucho tiempo.
Ehvince
9
  1. Yo uso el líder malvado y uso ", xm" para reemplazar "Mx", por lo que rara vez presiono la tecla Alt. También existe general.el, que admite múltiples claves de líder.

  2. evil-matchit , presione "%" para saltar entre pares de etiquetas.

  3. evil-nerd-commenter , presione "9, ci" para comentar / descomentar 9 líneas

  4. evite usar la tecla ESC, puede presionar "kj" en su lugar.

  5. ¡Tenga fe en el software libre! Nada es imposible con Evil, que combina el poder de Vim y Emacs. Por ejemplo, muchas personas asumen que las combinaciones de teclas Evil entran en conflicto con los complementos existentes de Emacs sin volver a vincularse fuertemente. Eso está mal en realidad

chen bin
fuente
0

Viniendo del lado de emacs, prefiero mucho M-. para ir a la definición, pero la función que se ejecuta M-.difiere entre los modos. Podría anularlo de la forma habitual con (define-key evil-normal-state-map (kbd "M-.") 'foo)where foocomprueba el modo principal actual y ejecuta la función adecuada, pero parece que requeriría mucha codificación. Una solución más general es esta:

(defun evil-emacs-key-binding (key)
  (evil-execute-in-emacs-state)
  (key-binding key))

(defmacro evil-revert-key-binding (state-map key)
  `(define-key ,state-map ,key (lambda ()
                                 (interactive)
                                 (call-interactively
                                  (evil-emacs-key-binding ,key)))))

(eval-after-load "evil-autoloads"
  '(add-hook 'evil-after-load-hook
        (lambda ()
          (evil-revert-key-binding evil-normal-state-map (kbd "M-."))
          ;; and so on
        )))

Aparte de eso, me gustan los complementos evil-surround (aunque creo que smartparens es una solución más completa) y evil-leader .

Solía ​​usar key-chord para mapear jk a ESC como aprendí a hacer en vim, pero insistía en tratar kj como lo mismo que jk, así que en su lugar estoy usando lo siguiente:

(defun evil-escape-if-next-char (trigger)
  "Watches the next letter. If `trigger', then switch to normal mode,
otherwise keep the previously inserted key and forward unpressed
key to `unread-command-events'."
  (self-insert-command 1)
  (let ((next-key (read-event)))
    (if (eq trigger next-key)
        (progn
          (delete-char -1)
          (evil-normal-state))
      (setq unread-command-events (cons next-key unread-command-events)))))

(defun evil-escape-if-next-char-is-k (arg)
  (interactive "p")
  (if (= arg 1)
      (evil-escape-if-next-char ?k)
    (self-insert-command arg)))

(eval-after-load "evil-autoloads"
  '(add-hook 'evil-after-load-hook
             (lambda ()
               ;; … other stuff …
               (define-key evil-insert-state-map (kbd "j") 'evil-escape-if-next-char-is-k))))

Yo uso (setq evil-move-cursor-back nil)que no es muy vimmy (aunque aparentemente puedes hacer que tu vimrc también lo haga), nunca me acostumbré a que el cursor se mueva hacia atrás después de salir de la inserción.

Consejo práctico: utilícelo evil-local-mode-hookpara cosas como carga diferida en modo envolvente maligno, no ayudará ponerlo en claro evil-mode-hook. Entonces, si instala evil y evil-surround con package-install, puede hacer que comience cuando lo haga M-x evil-modehaciendo

(eval-after-load "evil-surround-autoloads"
  '(add-hook 'evil-local-mode-hook #'evil-surround-mode))

(Por supuesto, si siempre ejecuta el modo malvado y siempre tiene mal instalado, no hay necesidad de ese material de carga automática, pero prefiero que mi .emacs sea lo suficientemente general como para poder usarlo en máquinas con emacsen antiguo o sin paquetes elpa instalados.)

desatornillar
fuente