Fix failure on depth 2+ nested snippets

* yasnippet.el (yas--advance-end-maybe-previous-fields): New function.
(yas--commit-snippet, yas--on-field-overlay-modification)
(yas-expand-snippet): Use it, so that all active fields will be
extended properly, even in case of deeply nested snippet expansion.
* yasnippet-tests.el (nested-snippet-expansion-depth-2): New test.
This commit is contained in:
Noam Postavsky 2020-03-25 20:45:21 -04:00
parent ac03c2f192
commit 7c02bc142c
2 changed files with 33 additions and 10 deletions

View File

@ -1099,6 +1099,24 @@ hello ${1:$(when (stringp yas-text) (funcall func yas-text))} foo${1:$$(concat \
(should (= (length (yas--snippet-fields (nth 0 snippets))) 2)) (should (= (length (yas--snippet-fields (nth 0 snippets))) 2))
(should (= (length (yas--snippet-fields (nth 1 snippets))) 1)))))) (should (= (length (yas--snippet-fields (nth 1 snippets))) 1))))))
(ert-deftest nested-snippet-expansion-depth-2 ()
(with-temp-buffer
(yas-with-snippet-dirs
'((".emacs.d/snippets"
("text-mode"
("nest" . "( $1"))))
(let ((yas-triggers-in-field t))
(yas-reload-all)
(text-mode)
(yas-minor-mode +1)
(dotimes (_ 3)
(yas-mock-insert "nest")
(ert-simulate-command '(yas-expand)))
(dotimes (_ 3)
(yas-mock-insert ")")
(ert-simulate-command '(yas-next-field-or-maybe-expand)))
))))
(ert-deftest nested-snippet-expansion-2 () (ert-deftest nested-snippet-expansion-2 ()
(let ((yas-triggers-in-field t)) (let ((yas-triggers-in-field t))
(yas-with-snippet-dirs (yas-with-snippet-dirs

View File

@ -3501,7 +3501,8 @@ This renders the snippet as ordinary text."
;; ;;
(let ((previous-field (yas--snippet-previous-active-field snippet))) (let ((previous-field (yas--snippet-previous-active-field snippet)))
(when (and yas-snippet-end previous-field) (when (and yas-snippet-end previous-field)
(yas--advance-end-maybe previous-field yas-snippet-end))) (yas--advance-end-maybe-previous-fields
previous-field yas-snippet-end (cdr yas--active-snippets))))
;; Convert all markers to points, ;; Convert all markers to points,
;; ;;
@ -3849,14 +3850,9 @@ field start. This hook does nothing if an undo is in progress."
(setf (yas--field-modified-p field) t) (setf (yas--field-modified-p field) t)
;; Adjust any pending active fields in case of stacked ;; Adjust any pending active fields in case of stacked
;; expansion. ;; expansion.
(let ((pfield field) (yas--advance-end-maybe-previous-fields
(psnippets (yas--gather-active-snippets field (overlay-end overlay)
overlay beg end t))) (yas--gather-active-snippets overlay beg end t))
(while (and pfield psnippets)
(let ((psnippet (pop psnippets)))
(cl-assert (memq pfield (yas--snippet-fields psnippet)))
(yas--advance-end-maybe pfield (overlay-end overlay))
(setq pfield (yas--snippet-previous-active-field psnippet)))))
;; Update fields now, but delay auto indentation until ;; Update fields now, but delay auto indentation until
;; post-command. We don't want to run indentation on ;; post-command. We don't want to run indentation on
;; the intermediate state where field text might be ;; the intermediate state where field text might be
@ -4110,7 +4106,9 @@ for normal snippets, and a list for command snippets)."
(overlay-get yas--active-field-overlay 'yas--field)))) (overlay-get yas--active-field-overlay 'yas--field))))
(when existing-field (when existing-field
(setf (yas--snippet-previous-active-field snippet) existing-field) (setf (yas--snippet-previous-active-field snippet) existing-field)
(yas--advance-end-maybe existing-field (overlay-end yas--active-field-overlay)))) (yas--advance-end-maybe-previous-fields
existing-field (overlay-end yas--active-field-overlay)
(cdr yas--active-snippets))))
;; Exit the snippet immediately if no fields. ;; Exit the snippet immediately if no fields.
(unless (yas--snippet-fields snippet) (unless (yas--snippet-fields snippet)
@ -4336,6 +4334,13 @@ exit-marker have identical start and end markers."
((yas--exit-p fom) ((yas--exit-p fom)
(yas--advance-start-maybe (yas--fom-next fom) newend)))) (yas--advance-start-maybe (yas--fom-next fom) newend))))
(defun yas--advance-end-maybe-previous-fields (field end snippets)
"Call `yas--advance-end-maybe' on FIELD, and previous fields on SNIPPETS."
(dolist (snippet snippets)
(cl-assert (memq field (yas--snippet-fields snippet)))
(yas--advance-end-maybe field end)
(setq field (yas--snippet-previous-active-field snippet))))
(defun yas--advance-start-maybe (fom newstart) (defun yas--advance-start-maybe (fom newstart)
"Maybe advance FOM's start to NEWSTART if it needs it. "Maybe advance FOM's start to NEWSTART if it needs it.