Activate extra and major modes first

This prevents snippets from a parent mode from overriding those of the
major-mode's (or yas--extra-modes).  Snippets of ancestor modes may
still override snippets of some other ancestor modes, but hopefully this
won't cause much trouble in practice.

See [1] and subsequent comments.

[1]: https://github.com/capitaomorte/yasnippet/issues/619#issuecomment-149127150

* yasnippet.el (yas--modes-to-activate): Reverse result, so that parents
  of yas--extra-modes and major are later in the list.
* yasnippet-tests.el (loading-with-cyclic-parenthood)
(extra-modes-parenthood): Test it.

Close #626.
This commit is contained in:
Noam Postavsky 2015-10-31 15:54:33 -04:00
parent b8687bb0fe
commit cd05da61f9
2 changed files with 34 additions and 31 deletions

View File

@ -497,6 +497,7 @@ TODO: correct this bug!"
emacs-lisp-mode emacs-lisp-mode
lisp-interaction-mode)) lisp-interaction-mode))
(observed (yas--modes-to-activate))) (observed (yas--modes-to-activate)))
(should (equal major-mode (car observed)))
(should (equal (sort expected #'string<) (sort observed #'string<)))))))) (should (equal (sort expected #'string<) (sort observed #'string<))))))))
(ert-deftest extra-modes-parenthood () (ert-deftest extra-modes-parenthood ()
@ -505,26 +506,29 @@ TODO: correct this bug!"
(yas-with-snippet-dirs '((".emacs.d/snippets" (yas-with-snippet-dirs '((".emacs.d/snippets"
("c-mode" ("c-mode"
(".yas-parents" . "cc-mode")) (".yas-parents" . "cc-mode"))
("cc-mode"
(".yas-parents" . "yet-another-c-mode and-that-one"))
("yet-another-c-mode" ("yet-another-c-mode"
(".yas-parents" . "c-mode and-also-this-one lisp-interaction-mode")))) (".yas-parents" . "c-mode and-also-this-one lisp-interaction-mode"))))
(yas-reload-all) (yas-reload-all)
(with-temp-buffer (with-temp-buffer
(let* ((_ (yas-activate-extra-mode 'c-mode)) (yas-activate-extra-mode 'c-mode)
(expected `(,major-mode (yas-activate-extra-mode 'yet-another-c-mode)
c-mode (yas-activate-extra-mode 'and-that-one)
cc-mode (let* ((expected-first `(and-that-one
yet-another-c-mode yet-another-c-mode
and-also-this-one c-mode
and-that-one ,major-mode))
(expected-rest `(cc-mode
;; prog-mode doesn't exist in emacs 24.3 ;; prog-mode doesn't exist in emacs 24.3
,@(if (fboundp 'prog-mode) ,@(if (fboundp 'prog-mode)
'(prog-mode)) '(prog-mode))
emacs-lisp-mode emacs-lisp-mode
and-also-this-one
lisp-interaction-mode)) lisp-interaction-mode))
(observed (yas--modes-to-activate))) (observed (yas--modes-to-activate)))
(should (equal (sort expected #'string<) (sort observed #'string<)))))))) (should (equal expected-first
(cl-subseq observed 0 (length expected-first))))
(should (equal (sort expected-rest #'string<)
(sort (cl-subseq observed (length expected-first)) #'string<))))))))
(ert-deftest issue-492-and-494 () (ert-deftest issue-492-and-494 ()
(defalias 'yas--phony-c-mode 'c-mode) (defalias 'yas--phony-c-mode 'c-mode)

View File

@ -728,22 +728,21 @@ defined direct keybindings to the command
(defun yas--modes-to-activate (&optional mode) (defun yas--modes-to-activate (&optional mode)
"Compute list of mode symbols that are active for `yas-expand' "Compute list of mode symbols that are active for `yas-expand'
and friends." and friends."
(let (dfs explored) (let* ((explored (if mode (list mode) ; Building up list in reverse.
(setq dfs (lambda (mode) (cons major-mode (reverse yas--extra-modes))))
(unless (memq mode explored) (dfs
(push mode explored) (lambda (mode)
(loop for neighbour (cl-loop for neighbour
in (cl-list* (get mode 'derived-mode-parent) in (cl-list* (get mode 'derived-mode-parent)
(ignore-errors (symbol-function mode)) (ignore-errors (symbol-function mode))
(gethash mode yas--parents)) (gethash mode yas--parents))
when (and neighbour when (and neighbour
(not (memq neighbour explored)) (not (memq neighbour explored))
(symbolp neighbour)) (symbolp neighbour))
do (funcall dfs neighbour))))) do (push neighbour explored)
(if mode (funcall dfs neighbour)))))
(funcall dfs mode) (mapcar dfs explored)
(mapcar dfs (cons major-mode yas--extra-modes))) (nreverse explored)))
explored))
(defvar yas-minor-mode-hook nil (defvar yas-minor-mode-hook nil
"Hook run when `yas-minor-mode' is turned on.") "Hook run when `yas-minor-mode' is turned on.")