Use expand-env for all snippet evaluations

* yasnippet.el (yas--snippet): New field, expand-env.
(yas--letenv): New macro, evaluate body with a given environment.
(yas--find-next-field, yas--safely-run-hooks):
(yas--on-field-overlay-modification):
(yas-expand-snippet, yas--snippet-create): Use it.
This commit is contained in:
Noam Postavsky 2016-12-02 19:32:21 -05:00
parent 5534cab0b7
commit 4ee3835adf

View File

@ -2902,10 +2902,11 @@ Use this in primary and mirror transformations to tget."
(put 'yas--active-field-overlay 'permanent-local t) (put 'yas--active-field-overlay 'permanent-local t)
(put 'yas--field-protection-overlays 'permanent-local t) (put 'yas--field-protection-overlays 'permanent-local t)
(cl-defstruct (yas--snippet (:constructor yas--make-snippet ())) (cl-defstruct (yas--snippet (:constructor yas--make-snippet (expand-env)))
"A snippet. "A snippet.
..." ..."
expand-env
(fields '()) (fields '())
(exit nil) (exit nil)
(id (yas--snippet-next-id) :read-only t) (id (yas--snippet-next-id) :read-only t)
@ -2954,6 +2955,12 @@ DEPTH is a count of how many nested mirrors can affect this mirror"
marker marker
next) next)
(defmacro yas--letenv (env &rest body)
"Evaluate BODY with bindings from ENV.
ENV is a list of elements with the form (VAR FORM)."
(declare (debug (form body)) (indent 1))
`(eval (cl-list* 'let* ,env ',body)))
(defun yas--apply-transform (field-or-mirror field &optional empty-on-nil-p) (defun yas--apply-transform (field-or-mirror field &optional empty-on-nil-p)
"Calculate transformed string for FIELD-OR-MIRROR from FIELD. "Calculate transformed string for FIELD-OR-MIRROR from FIELD.
@ -3102,15 +3109,16 @@ If there's none, exit the snippet."
(let* ((snippet (car (yas-active-snippets))) (let* ((snippet (car (yas-active-snippets)))
(active-field (overlay-get yas--active-field-overlay 'yas--field)) (active-field (overlay-get yas--active-field-overlay 'yas--field))
(target-field (yas--find-next-field arg snippet active-field))) (target-field (yas--find-next-field arg snippet active-field)))
;; Apply transform to active field. (yas--letenv (yas--snippet-expand-env snippet)
(when active-field ;; Apply transform to active field.
(let ((yas-moving-away-p t)) (when active-field
(when (yas--field-update-display active-field) (let ((yas-moving-away-p t))
(yas--update-mirrors snippet)))) (when (yas--field-update-display active-field)
;; Now actually move... (yas--update-mirrors snippet))))
(if target-field ;; Now actually move...
(yas--move-to-field snippet target-field) (if target-field
(yas-exit-snippet snippet)))) (yas--move-to-field snippet target-field)
(yas-exit-snippet snippet)))))
(defun yas--place-overlays (snippet field) (defun yas--place-overlays (snippet field)
"Correctly place overlays for SNIPPET's FIELD." "Correctly place overlays for SNIPPET's FIELD."
@ -3239,25 +3247,26 @@ If so cleans up the whole snippet up."
(snippet-exit-transform)) (snippet-exit-transform))
(dolist (snippet snippets) (dolist (snippet snippets)
(let ((active-field (yas--snippet-active-field snippet))) (let ((active-field (yas--snippet-active-field snippet)))
(setq snippet-exit-transform (yas--snippet-force-exit snippet)) (yas--letenv (yas--snippet-expand-env snippet)
(cond ((or snippet-exit-transform (setq snippet-exit-transform (yas--snippet-force-exit snippet))
(not (and active-field (yas--field-contains-point-p active-field)))) (cond ((or snippet-exit-transform
(setq snippets-left (delete snippet snippets-left)) (not (and active-field (yas--field-contains-point-p active-field))))
(setf (yas--snippet-force-exit snippet) nil) (setq snippets-left (delete snippet snippets-left))
(yas--commit-snippet snippet)) (setf (yas--snippet-force-exit snippet) nil)
((and active-field (yas--commit-snippet snippet))
(or (not yas--active-field-overlay) ((and active-field
(not (overlay-buffer yas--active-field-overlay)))) (or (not yas--active-field-overlay)
;; (not (overlay-buffer yas--active-field-overlay))))
;; stacked expansion: this case is mainly for recent ;;
;; snippet exits that place us back int the field of ;; stacked expansion: this case is mainly for recent
;; another snippet ;; snippet exits that place us back int the field of
;; ;; another snippet
(save-excursion ;;
(yas--move-to-field snippet active-field) (save-excursion
(yas--update-mirrors snippet))) (yas--move-to-field snippet active-field)
(t (yas--update-mirrors snippet)))
nil)))) (t
nil)))))
(unless (or (null snippets) snippets-left) (unless (or (null snippets) snippets-left)
(if snippet-exit-transform (if snippet-exit-transform
(yas--eval-lisp-no-saves snippet-exit-transform)) (yas--eval-lisp-no-saves snippet-exit-transform))
@ -3428,14 +3437,15 @@ field start. This hook does nothing if an undo is in progress."
(field (overlay-get overlay 'yas--field)) (field (overlay-get overlay 'yas--field))
(snippet (overlay-get yas--active-field-overlay 'yas--snippet))) (snippet (overlay-get yas--active-field-overlay 'yas--snippet)))
(save-match-data (save-match-data
(when (yas--skip-and-clear-field-p field beg end length) (yas--letenv (yas--snippet-expand-env snippet)
;; We delete text starting from the END of insertion. (when (yas--skip-and-clear-field-p field beg end length)
(yas--skip-and-clear field end)) ;; We delete text starting from the END of insertion.
(setf (yas--field-modified-p field) t) (yas--skip-and-clear field end))
(yas--advance-end-maybe field (overlay-end overlay)) (setf (yas--field-modified-p field) t)
(save-excursion (yas--advance-end-maybe field (overlay-end overlay))
(yas--field-update-display field)) (save-excursion
(yas--update-mirrors snippet))))) (yas--field-update-display field))
(yas--update-mirrors snippet))))))
;;; Apropos protection overlays: ;;; Apropos protection overlays:
;; ;;
@ -3582,13 +3592,9 @@ considered when expanding the snippet."
;; insert things that are not valid in the ;; insert things that are not valid in the
;; major-mode language syntax anyway. ;; major-mode language syntax anyway.
(syntax-propertize-function nil)) (syntax-propertize-function nil))
(insert content)
(setq snippet (setq snippet
(if expand-env (yas--snippet-create expand-env start (point))))
(eval `(let* ,expand-env
(insert content)
(yas--snippet-create start (point))))
(insert content)
(yas--snippet-create start (point)))))
;; Invalidate any syntax-propertizing done while `syntax-propertize-function' was nil ;; Invalidate any syntax-propertizing done while `syntax-propertize-function' was nil
(syntax-ppss-flush-cache start)) (syntax-ppss-flush-cache start))
@ -3668,27 +3674,28 @@ After revival, push the `yas--take-care-of-redo' in the
(push `(apply yas--take-care-of-redo ,beg ,end ,snippet) (push `(apply yas--take-care-of-redo ,beg ,end ,snippet)
buffer-undo-list)))) buffer-undo-list))))
(defun yas--snippet-create (begin end) (defun yas--snippet-create (expand-env begin end)
"Create a snippet from a template inserted at BEGIN to END. "Create a snippet from a template inserted at BEGIN to END.
Returns the newly created snippet." Returns the newly created snippet."
(save-restriction (save-restriction
(narrow-to-region begin end) (narrow-to-region begin end)
(let ((snippet (yas--make-snippet))) (let ((snippet (yas--make-snippet expand-env)))
(goto-char begin) (yas--letenv expand-env
(yas--snippet-parse-create snippet) (goto-char begin)
(yas--snippet-parse-create snippet)
;; Sort and link each field ;; Sort and link each field
(yas--snippet-sort-fields snippet) (yas--snippet-sort-fields snippet)
;; Create keymap overlay for snippet ;; Create keymap overlay for snippet
(setf (yas--snippet-control-overlay snippet) (setf (yas--snippet-control-overlay snippet)
(yas--make-control-overlay snippet (point-min) (point-max))) (yas--make-control-overlay snippet (point-min) (point-max)))
;; Move to end ;; Move to end
(goto-char (point-max)) (goto-char (point-max))
snippet))) snippet))))
;;; Apropos adjacencies and "fom's": ;;; Apropos adjacencies and "fom's":