Don't use overlays to find active snippets

* yasnippet.el (yas--active-snippets): New buffer-local variable.
(yas-active-snippets): Use it, when asked for all active snippets.
(yas--commit-snippet): Remove finished snippet from list of active
snippets.
(yas--snippet-create): Add new snippet to list of active snippets.
(yas--check-commit-snippet): Consult list of active snippetes.
This commit is contained in:
Noam Postavsky 2018-04-10 22:30:15 -04:00
parent 4af33546d8
commit e67592ce1b

View File

@ -3070,6 +3070,10 @@ other fields."
(defvar yas--active-field-overlay nil (defvar yas--active-field-overlay nil
"Overlays the currently active field.") "Overlays the currently active field.")
(defvar yas--active-snippets nil
"List of currently active snippets")
(make-variable-buffer-local 'yas--active-snippets)
(defvar yas--field-protection-overlays nil (defvar yas--field-protection-overlays nil
"Two overlays protect the current active field.") "Two overlays protect the current active field.")
@ -3273,19 +3277,19 @@ equivalent to a range covering the whole buffer."
(setq beg (point-min) end (point-max))) (setq beg (point-min) end (point-max)))
((not end) ((not end)
(setq end (1+ beg)))) (setq end (1+ beg))))
(if (and (eq beg (point-min))
;; Note: don't use `mapcar' here, since it would allocate in (eq end (point-max)))
;; proportion to the amount of overlays, even though the list of yas--active-snippets
;; active snippets should be very small. That is important because ;; Note: don't use `mapcar' here, since it would allocate in
;; this function is called in the post-command hook (via ;; proportion to the amount of overlays, even though the list of
;; `yas--check-commit-snippet'). ;; active snippets should be very small.
(let ((snippets nil)) (let ((snippets nil))
(dolist (ov (overlays-in beg end)) (dolist (ov (overlays-in beg end))
(let ((snippet (overlay-get ov 'yas--snippet))) (let ((snippet (overlay-get ov 'yas--snippet)))
;; Snippets have multiple overlays, so check for dups. ;; Snippets have multiple overlays, so check for dups.
(when (and snippet (not (memq snippet snippets))) (when (and snippet (not (memq snippet snippets)))
(push snippet snippets)))) (push snippet snippets))))
(cl-sort snippets #'>= :key #'yas--snippet-id))) (cl-sort snippets #'>= :key #'yas--snippet-id))))
(define-obsolete-function-alias 'yas--snippets-at-point (define-obsolete-function-alias 'yas--snippets-at-point
'yas-active-snippets "0.12") 'yas-active-snippets "0.12")
@ -3445,6 +3449,9 @@ This renders the snippet as ordinary text."
;; ;;
(yas--markers-to-points snippet) (yas--markers-to-points snippet)
;; It's no longer an active snippet.
(cl-callf2 delq snippet yas--active-snippets)
;; Take care of snippet revival on undo. ;; Take care of snippet revival on undo.
(if (and yas-snippet-revival (listp buffer-undo-list)) (if (and yas-snippet-revival (listp buffer-undo-list))
(push `(apply yas--snippet-revive ,yas-snippet-beg ,yas-snippet-end ,snippet) (push `(apply yas--snippet-revive ,yas-snippet-beg ,yas-snippet-end ,snippet)
@ -3538,13 +3545,12 @@ HOOK should be a symbol, a hook variable, as in `run-hooks'."
"Check if point exited the currently active field of the snippet. "Check if point exited the currently active field of the snippet.
If so cleans up the whole snippet up." If so cleans up the whole snippet up."
(let* ((snippets (yas-active-snippets 'all)) (let* ((snippet-exit-transform nil)
(snippets-left snippets) (exited-snippets-p nil)
(snippet-exit-transform)
;; Record the custom snippet `yas-after-exit-snippet-hook' ;; Record the custom snippet `yas-after-exit-snippet-hook'
;; set in the expand-env field. ;; set in the expand-env field.
(snippet-exit-hook yas-after-exit-snippet-hook)) (snippet-exit-hook yas-after-exit-snippet-hook))
(dolist (snippet snippets) (dolist (snippet yas--active-snippets)
(let ((active-field (yas--snippet-active-field snippet))) (let ((active-field (yas--snippet-active-field snippet)))
(yas--letenv (yas--snippet-expand-env snippet) (yas--letenv (yas--snippet-expand-env snippet)
;; Note: the `force-exit' field could be a transform in case of ;; Note: the `force-exit' field could be a transform in case of
@ -3552,10 +3558,10 @@ If so cleans up the whole snippet up."
(setq snippet-exit-transform (yas--snippet-force-exit snippet)) (setq snippet-exit-transform (yas--snippet-force-exit snippet))
(cond ((or snippet-exit-transform (cond ((or snippet-exit-transform
(not (and active-field (yas--field-contains-point-p active-field)))) (not (and active-field (yas--field-contains-point-p active-field))))
(setq snippets-left (delete snippet snippets-left))
(setf (yas--snippet-force-exit snippet) nil) (setf (yas--snippet-force-exit snippet) nil)
(setq snippet-exit-hook yas-after-exit-snippet-hook) (setq snippet-exit-hook yas-after-exit-snippet-hook)
(yas--commit-snippet snippet)) (yas--commit-snippet snippet)
(setq exited-snippets-p t))
((and active-field ((and active-field
(or (not yas--active-field-overlay) (or (not yas--active-field-overlay)
(not (overlay-buffer yas--active-field-overlay)))) (not (overlay-buffer yas--active-field-overlay))))
@ -3569,7 +3575,7 @@ If so cleans up the whole snippet up."
(yas--update-mirrors snippet))) (yas--update-mirrors snippet)))
(t (t
nil))))) nil)))))
(unless (or (null snippets) snippets-left) (unless (or yas--active-snippets (not exited-snippets-p))
(when snippet-exit-transform (when snippet-exit-transform
(yas--eval-for-effect snippet-exit-transform)) (yas--eval-for-effect snippet-exit-transform))
(let ((yas-after-exit-snippet-hook snippet-exit-hook)) (let ((yas-after-exit-snippet-hook snippet-exit-hook))
@ -4062,6 +4068,7 @@ Returns the newly created snippet."
;; Move to end ;; Move to end
(goto-char (point-max)) (goto-char (point-max))
(push snippet yas--active-snippets)
snippet)))) snippet))))