Revert hybrid mode to use an evil hybrid state

To follow with the refactor of the holy-mode which uses the
emacs state of evil mode, the hybrid mode now uses the evil hybrid
state.

We have now a clean symmetry between all the editing styles where each
of them has an associated state:
- vim = insert state
- emacs = emacs state
- hybrid = hybrid state

This gives consistent properties to all editing styles and most
importantly allows to have true isolation of key binding maps. It has
the huge benefit to be easier to explain since now everything can
leverage the evil API regarding key bindings.

Note: Regular Emacs key binding functions can still be used for emacs
and hybrid states so there is no regression with the previous
implementation, we just gain better isolation at the cost of a few
duplicated lines of code which will be easy to update as needed if
evil upstream code changes (this code has been commented with a link
to the upstream code).
This commit is contained in:
syl20bnr 2016-03-16 21:30:03 -04:00
parent 82fdd9a511
commit cfdfcfab40
3 changed files with 73 additions and 58 deletions

View File

@ -360,13 +360,6 @@
(evil-define-key 'insert comint-mode-map [up] 'comint-previous-input)
(evil-define-key 'insert comint-mode-map [down] 'comint-next-input))
;; ivy/helm keys --------------------------------------------------------------
(defvar spacemacs-editing-style-hook nil
"Hook run whenever an editing style is toggled.
Each function in the hook is run with a single argument which is the current
editing style.")
;; ---------------------------------------------------------------------------
;; Transient-states
;; ---------------------------------------------------------------------------

View File

@ -0,0 +1,15 @@
;;; config.el --- editing-style Layer configuration File for Spacemacs
;;
;; Copyright (c) 2012-2016 Sylvain Benner & Contributors
;;
;; Author: Sylvain Benner <sylvain.benner@gmail.com>
;; URL: https://github.com/syl20bnr/spacemacs
;;
;; This file is not part of GNU Emacs.
;;
;;; License: GPLv3
(defvar spacemacs-editing-style-hook nil
"Hook run whenever an editing style is toggled.
Each function in the hook is run with a single argument which is the current
editing style.")

View File

@ -40,65 +40,72 @@ to start in hybrid state (emacs bindings) by default."
:group 'spacemacs
:type 'symbol)
(defvar hybrid-mode-insert-cursor evil-hybrid-state-cursor)
(defvar hybrid-mode-insert-cursor-backup evil-insert-state-cursor)
(defvar hybrid-mode-insert-state-entry-hook)
(defvar hybrid-mode-insert-state-exit-hook)
(defun hybrid-mode-insert-state-entry-hook ()
"Run hooks in `hybrid-mode-insert-state-entry-hook'."
(run-hooks 'hybrid-mode-insert-state-entry-hook))
(defun hybrid-mode-insert-state-exit-hook ()
"Run hooks in `hybrid-mode-insert-state-exit-hook'."
(run-hooks 'hybrid-mode-insert-state-exit-hook))
(defadvice evil-insert-state (around hybrid-insert-to-hybrid-state disable)
"Forces Hybrid state."
(evil-hybrid-state))
;;;###autoload
(define-minor-mode hybrid-mode
"Global minor mode to allow emacs bindings in `evil-insert-state'."
"Global minor mode to replace insert state by hybrid state."
:global t
:lighter " hybrid"
:group 'spacemacs
(if hybrid-mode
(progn
(setq hybrid-mode-default-state-backup evil-default-state
evil-default-state hybrid-mode-default-state
evil-insert-state-cursor hybrid-mode-insert-cursor)
(put 'spacemacs-insert-face 'face-alias 'spacemacs-hybrid-face)
;; using this function to set the variable triggers the defcustom :set
;; property which actually does the work of removing the bindings.
(customize-set-variable 'evil-disable-insert-state-bindings t)
(add-hook 'evil-insert-state-entry-hook 'hybrid-mode-insert-state-entry-hook)
(add-hook 'evil-insert-state-exit-hook 'hybrid-mode-insert-state-exit-hook))
(setq evil-default-state hybrid-mode-default-state-backup
evil-insert-state-cursor hybrid-mode-insert-cursor-backup)
(put 'spacemacs-insert-face 'face-alias nil)
(customize-set-variable 'evil-disable-insert-state-bindings nil)
(remove-hook 'evil-insert-state-entry-hook 'hybrid-mode-insert-state-entry-hook)
(remove-hook 'evil-insert-state-exit-hook 'hybrid-mode-insert-state-exit-hook)))
(enable-hybrid-editing-style)
(enable-hybrid-editing-style)))
;;; Temporary to support old method of defining bindings. Should be removed
;;; eventually.
(when (fboundp 'advice-add)
(defun hybrid-mode-evil-define-key (old-func &rest args)
(if (equal (car args) ''hybrid)
(let ((map (nth 1 args))
(key (nth 2 args))
(def (nth 3 args))
(bindings (nthcdr 4 args)))
(message "warning: evil-define-key no longer supports \
hybrid as a state please convert to (define-key map key def)")
(while key
(when (keymapp (symbol-value map))
(define-key (symbol-value map) key def)
(setq key (pop bindings)
def (pop bindings)))))
(apply old-func args)))
(advice-add 'evil-define-key :around #'hybrid-mode-evil-define-key))
(defun enable-hybrid-editing-style ()
"Enable the hybrid editing style."
(setq hybrid-mode-default-state-backup evil-default-state
evil-default-state hybrid-mode-default-state)
;; key bindings hooks for dynamic switching of editing styles
(run-hook-with-args 'spacemacs-editing-style-hook 'hybrid)
(ad-enable-advice 'evil-insert-state
'around 'hybrid-insert-to-hybrid-state)
(ad-activate 'evil-insert-state))
(defvar evil-hybrid-state-map
(let ((map (make-sparse-keymap)))
(set-keymap-parent evil-insert-state-map map)
map))
(defun disable-hybrid-editing-style ()
"Disable the hybrid editing style (reverting to 'vim style)."
(setq evil-default-state hybrid-mode-default-state-backup)
;; restore key bindings
(run-hook-with-args 'spacemacs-editing-style-hook 'vim)
(ad-disable-advice 'evil-insert-state
'around 'hybrid-insert-to-hybrid-state)
(ad-activate 'evil-insert-state))
;; This code is from evil insert state definition, any change upstream
;; should be reflected here
;; see https://bitbucket.org/lyro/evil/src/a25b848c90c7942fe89d9ec283c6bb44fb7b3cf4/evil-states.el?fileviewer=file-view-default#evil-states.el-74
(evil-define-state hybrid
"Hybrid state for hybrid mode."
:tag " <H> "
:cursor (bar . 2)
:message "-- HYBRID --"
:entry-hook (evil-start-track-last-insertion)
:exit-hook (evil-cleanup-insert-state evil-stop-track-last-insertion)
:input-method t
(cond
((evil-hybrid-state-p)
(add-hook 'pre-command-hook #'evil-insert-repeat-hook)
(unless (eq evil-want-fine-undo t)
(evil-start-undo-step t)))
(t
(remove-hook 'pre-command-hook #'evil-insert-repeat-hook)
(setq evil-insert-repeat-info evil-repeat-info)
(evil-set-marker ?^ nil t)
(unless (eq evil-want-fine-undo t)
(evil-end-undo-step t (eq evil-want-fine-undo 'fine)))
(when evil-move-cursor-back
(when (or (evil-normal-state-p evil-next-state)
(evil-motion-state-p evil-next-state))
(evil-move-cursor-back))))))
(define-key evil-hybrid-state-map [escape] 'evil-normal-state)
;; Override stock evil function `evil-insert-state-p'
(defun evil-insert-state-p (&optional state)
"Whether the current state is insert."
(and evil-local-mode
(memq (or state evil-state) '(insert hybrid))))
(provide 'hybrid-mode)