aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVasilij Schneidermann <mail@vasilij.de>2018-01-26 20:59:07 +0100
committerGitHub <noreply@github.com>2018-01-26 20:59:07 +0100
commit2992858748e6fe8ae706d182b86b684e7b9be8b9 (patch)
tree022042b549c70a023ad8dfe2d2b1a00815d6248a
parent99192e6f3135f35941da9fceafa1401124fe3374 (diff)
parentfa512647366ff62a190f0721e6161b4279f128fe (diff)
Merge pull request #985 from justbur/derived-modes-2
Rework #984
-rw-r--r--evil-core.el43
-rw-r--r--evil-tests.el42
2 files changed, 74 insertions, 11 deletions
diff --git a/evil-core.el b/evil-core.el
index 125c166..eb23eed 100644
--- a/evil-core.el
+++ b/evil-core.el
@@ -282,21 +282,42 @@ See also `evil-initial-state'."
(when (and (boundp mode) (symbol-value mode))
(when (setq mode (evil-initial-state mode))
(throw 'done mode)))))
- (evil-initial-state major-mode)
+ (evil-initial-state major-mode nil t)
default)))
-(defun evil-initial-state (mode &optional default)
- "Return the Evil state to use for MODE.
+(defun evil-initial-state (mode &optional default follow-parent checked-modes)
+ "Return the Evil state to use for MODE or its alias.
Returns DEFAULT if no initial state is associated with MODE.
The initial state for a mode can be set with
-`evil-set-initial-state'."
- (let (state modes)
- (catch 'done
- (dolist (entry (evil-state-property t :modes) default)
- (setq state (car entry)
- modes (symbol-value (cdr entry)))
- (when (memq mode modes)
- (throw 'done state))))))
+`evil-set-initial-state'.
+
+If FOLLOW-PARENT is non-nil, also check parent modes of MODE and
+its alias. CHECKED-MODES is used internally and should not be set
+initially."
+ (cond
+ ((and mode (symbolp mode) (memq mode checked-modes))
+ (error "Circular reference detected in ancestors of %s\n%s"
+ major-mode checked-modes))
+ ((and mode (symbolp mode))
+ (let ((mode-alias (let ((func (symbol-function mode)))
+ (when (symbolp func)
+ func)))
+ state modes)
+ (or
+ (catch 'done
+ (dolist (entry (evil-state-property t :modes) default)
+ (setq state (car entry)
+ modes (symbol-value (cdr entry)))
+ (when (or (memq mode modes)
+ (and mode-alias
+ (memq mode-alias modes)))
+ (throw 'done state))))
+ (when follow-parent
+ (evil-initial-state (get mode 'derived-mode-parent)
+ nil t (cons mode checked-modes)))
+ (when follow-parent
+ (evil-initial-state (get mode-alias 'derived-mode-parent)
+ nil t (cons mode-alias checked-modes))))))))
(defun evil-set-initial-state (mode state)
"Set the initial state for MODE to STATE.
diff --git a/evil-tests.el b/evil-tests.el
index 75b28b4..50edebd 100644
--- a/evil-tests.el
+++ b/evil-tests.el
@@ -8257,6 +8257,48 @@ when an error stops the execution of the macro"
; should not raise an "Selecting deleted buffer" error
(evil-visual-update-x-selection buf))))
+;;; Core
+
+(ert-deftest evil-test-initial-state ()
+ "Test `evil-initial-state'"
+ :tags '(evil core)
+ (define-derived-mode test-1-mode prog-mode "Test1")
+ (define-derived-mode test-2-mode test-1-mode "Test2")
+ (evil-set-initial-state 'test-1-mode 'insert)
+ (ert-info ("Check default state")
+ (should (eq (evil-initial-state 'prog-mode 'normal) 'normal)))
+ (ert-info ("Basic functionality 1")
+ (should (eq (evil-initial-state 'test-1-mode) 'insert)))
+ (ert-info ("Basic functionality 2")
+ (evil-test-buffer
+ "abc\ndef\n"
+ (test-1-mode)
+ (should (eq evil-state 'insert))))
+ (ert-info ("Inherit initial state from a parent")
+ (evil-test-buffer
+ "abc\ndef\n"
+ (test-2-mode)
+ (should (eq evil-state 'insert))))
+ (evil-set-initial-state 'test-1-mode nil)
+ (ert-info ("Check for inheritance loops")
+ (evil-test-buffer
+ "abc\ndef\n"
+ (unwind-protect
+ (let ((major-mode 'test-2-mode))
+ (put 'test-1-mode 'derived-mode-parent 'test-2-mode)
+ ;; avoid triggering all of the hooks here, some of which might get
+ ;; caught in loops depending on the environment. settings major-mode
+ ;; is sufficient for `evil-initial-state-for-buffer' to work.
+ (should-error (evil-initial-state-for-buffer)))
+ (put 'test-1-mode 'derived-mode-parent 'prog-mode))))
+ (defalias 'test-1-alias-mode 'test-1-mode)
+ (define-derived-mode test-3-mode test-1-alias-mode "Test3")
+ (evil-set-initial-state 'test-1-mode 'insert)
+ (ert-info ("Check inheritance from major mode aliases")
+ "abc\ndef\n"
+ (test-3-mode)
+ (should (eq evil-state 'insert))))
+
(provide 'evil-tests)
;;; evil-tests.el ends here