diff options
| author | Vasilij Schneidermann <mail@vasilij.de> | 2018-01-26 20:59:07 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-01-26 20:59:07 +0100 |
| commit | 2992858748e6fe8ae706d182b86b684e7b9be8b9 (patch) | |
| tree | 022042b549c70a023ad8dfe2d2b1a00815d6248a | |
| parent | 99192e6f3135f35941da9fceafa1401124fe3374 (diff) | |
| parent | fa512647366ff62a190f0721e6161b4279f128fe (diff) | |
Merge pull request #985 from justbur/derived-modes-2
Rework #984
| -rw-r--r-- | evil-core.el | 43 | ||||
| -rw-r--r-- | evil-tests.el | 42 |
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 |
