[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[elpa] master c432e78 31/42: Fix field adjustment on deletion
From: |
Noam Postavsky |
Subject: |
[elpa] master c432e78 31/42: Fix field adjustment on deletion |
Date: |
Sun, 22 Dec 2019 17:38:02 -0500 (EST) |
branch: master
commit c432e78ffd7f09b3b1868345ff80001a6bbe2ee6
Author: Noam Postavsky <address@hidden>
Commit: Noam Postavsky <address@hidden>
Fix field adjustment on deletion
For deletion, we need to check the bounds before the deletion happens,
otherwise the overlay may already be moved to wrong place.
* yasnippet.el (yas--before-change-modified-snippets): New variable.
(yas--merge-and-drop-dups): New function.
(yas--gather-active-snippets): New function.
(yas--on-field-overlay-modification): Use it.
* yasnippet.el
---
yasnippet-tests.el | 21 ++++++++++++
yasnippet.el | 94 +++++++++++++++++++++++++++++++++++++-----------------
2 files changed, 86 insertions(+), 29 deletions(-)
diff --git a/yasnippet-tests.el b/yasnippet-tests.el
index db9c177..7791db8 100644
--- a/yasnippet-tests.el
+++ b/yasnippet-tests.el
@@ -1122,6 +1122,27 @@ hello ${1:$(when (stringp yas-text) (funcall func
yas-text))} foo${1:$$(concat \
(ert-simulate-command '(yas-next-field-or-maybe-expand))
(should (string= (buffer-string) "<-<-abcdef\n")))))
+(ert-deftest nested-snippet-expansion-5-nested-delete ()
+ "See Github #996."
+ (let ((yas-triggers-in-field t))
+ (yas-with-snippet-dirs
+ '((".emacs.d/snippets"
+ ("text-mode"
+ ("sel" . "${1:ch}")
+ ("ch" . "<-${1:ch}"))))
+ (yas-reload-all)
+ (text-mode)
+ (yas-minor-mode +1)
+ (insert "sel")
+ (ert-simulate-command '(yas-expand))
+ (ert-simulate-command '(forward-word 1))
+ (ert-simulate-command '(yas-expand))
+ (ert-simulate-command '(forward-word 1))
+ ;; The (cl-assert (memq pfield (yas--snippet-fields psnippet)))
+ ;; in `yas--on-field-overlay-modification' failed here.
+ (ert-simulate-command '(delete-backward-char 1))
+ (should (string= (buffer-string) "<-c\n")))))
+
;;; Loading
;;;
diff --git a/yasnippet.el b/yasnippet.el
index 2ec192a..27df486 100644
--- a/yasnippet.el
+++ b/yasnippet.el
@@ -3788,13 +3788,45 @@ BEG, END and LENGTH like overlay modification hooks."
(defvar yas--todo-snippet-indent nil nil)
(make-variable-buffer-local 'yas--todo-snippet-indent)
+(defvar yas--before-change-modified-snippets nil)
+
+(defun yas--merge-and-drop-dups (list1 list2 cmp key)
+ ;; `delete-consecutive-dups' + `cl-merge'.
+ (funcall (if (fboundp 'delete-consecutive-dups)
+ #'delete-consecutive-dups ; 24.4
+ #'delete-dups)
+ (cl-merge 'list list1 list2 cmp :key key)))
+
+(defun yas--gather-active-snippets (overlay beg end then-delete)
+ ;; Add active snippets in BEG..END into an OVERLAY keyed entry of
+ ;; `yas--before-change-modified-snippets'. Return accumulated list.
+ ;; If THEN-DELETE is non-nil, delete the entry.
+ (let ((new (yas-active-snippets beg end))
+ (old (assq overlay yas--before-change-modified-snippets)))
+ (prog1 (cond ((and new old)
+ (setf (cdr old)
+ (yas--merge-and-drop-dups
+ (cdr old) new
+ ;; Sort like `yas-active-snippets'.
+ #'>= #'yas--snippet-id)))
+ (new (unless then-delete
+ ;; Don't add new entry if we're about to
+ ;; remove it anyway.
+ (push (cons overlay new)
+ yas--before-change-modified-snippets))
+ new)
+ (old (cdr old))
+ (t nil))
+ (when then-delete
+ (cl-callf2 delq old yas--before-change-modified-snippets)))))
+
+
(defun yas--on-field-overlay-modification (overlay after? beg end &optional
length)
"Clears the field and updates mirrors, conditionally.
Only clears the field if it hasn't been modified and point is at
field start. This hook does nothing if an undo is in progress."
- (unless (or (not after?)
- yas--inhibit-overlay-hooks
+ (unless (or yas--inhibit-overlay-hooks
(not (overlayp yas--active-field-overlay)) ; Avoid Emacs bug
#21824.
;; If a single change hits multiple overlays of the same
;; snippet, then we delete the snippet the first time,
@@ -3807,33 +3839,37 @@ field start. This hook does nothing if an undo is in
progress."
(field (overlay-get overlay 'yas--field))
(snippet (overlay-get yas--active-field-overlay 'yas--snippet)))
(if (yas--snippet-live-p snippet)
- (save-match-data
- (yas--letenv (yas--snippet-expand-env snippet)
- (when (yas--skip-and-clear-field-p field beg end length)
- ;; We delete text starting from the END of insertion.
- (yas--skip-and-clear field end))
- (setf (yas--field-modified-p field) t)
- ;; Adjust any pending active fields in case of stacked
- ;; expansion.
- (let ((pfield field)
- (psnippets (yas-active-snippets beg end)))
- (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
- ;; post-command. We don't want to run indentation on
- ;; the intermediate state where field text might be
- ;; removed (and hence the field could be deleted along
- ;; with leading indentation).
- (let ((yas-indent-line nil))
- (save-excursion
- (yas--field-update-display field))
- (yas--update-mirrors snippet))
- (unless (or (not (eq yas-indent-line 'auto))
- (memq snippet yas--todo-snippet-indent))
- (push snippet yas--todo-snippet-indent))))
+ (if after?
+ (save-match-data
+ (yas--letenv (yas--snippet-expand-env snippet)
+ (when (yas--skip-and-clear-field-p field beg end length)
+ ;; We delete text starting from the END of insertion.
+ (yas--skip-and-clear field end))
+ (setf (yas--field-modified-p field) t)
+ ;; Adjust any pending active fields in case of stacked
+ ;; expansion.
+ (let ((pfield field)
+ (psnippets (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
+ ;; post-command. We don't want to run indentation on
+ ;; the intermediate state where field text might be
+ ;; removed (and hence the field could be deleted along
+ ;; with leading indentation).
+ (let ((yas-indent-line nil))
+ (save-excursion
+ (yas--field-update-display field))
+ (yas--update-mirrors snippet))
+ (unless (or (not (eq yas-indent-line 'auto))
+ (memq snippet yas--todo-snippet-indent))
+ (push snippet yas--todo-snippet-indent))))
+ ;; Remember active snippets to use for after the change.
+ (yas--gather-active-snippets overlay beg end nil))
(lwarn '(yasnippet zombie) :warning "Killing zombie snippet!")
(delete-overlay overlay)))))
- [elpa] master 9cedd59 25/42: Allow disabling snippet keybindings from hook, (continued)
- [elpa] master 9cedd59 25/42: Allow disabling snippet keybindings from hook, Noam Postavsky, 2019/12/22
- [elpa] master 55c448b 32/42: Remove redundant arg to yas-expand-snippet, Noam Postavsky, 2019/12/22
- [elpa] master 189f737 26/42: * doc/faq.org: Note that Flyspell problem is (now fixed) Emacs bug., Noam Postavsky, 2019/12/22
- [elpa] master ffce236 30/42: Do auto indentation only in post command hook, Noam Postavsky, 2019/12/22
- [elpa] master 760f77a 12/42: Test for mirroring more than one field, Noam Postavsky, 2019/12/22
- [elpa] master 0f05a75 14/42: Add yas-completing-read, Noam Postavsky, 2019/12/22
- [elpa] master 03aa561 19/42: * doc/snippet-organization.org: Fix typo., Noam Postavsky, 2019/12/22
- [elpa] master 9f51cf2 17/42: Register snippet movement comments for eldoc, Noam Postavsky, 2019/12/22
- [elpa] master 6a738b5 29/42: ; doc/faq.org: Fix example keybinding code., Noam Postavsky, 2019/12/22
- [elpa] master 476bc77 35/42: Fix snippet undo, Noam Postavsky, 2019/12/22
- [elpa] master c432e78 31/42: Fix field adjustment on deletion,
Noam Postavsky <=
- [elpa] master f056a4d 33/42: Minor code shuffling and commenting, Noam Postavsky, 2019/12/22
- [elpa] master bd3572a 36/42: Handle multiple uses of yas-auto-next, Noam Postavsky, 2019/12/22
- [elpa] master e45e3de 34/42: * doc/faq.org: yas-prev should be yas-prev-field, Noam Postavsky, 2019/12/22
- [elpa] master a66f15e 38/42: Fix yas-insert-snippet for keyless snippets, Noam Postavsky, 2019/12/22
- [elpa] master d91dd66 37/42: * yasnippet.el (yas--extra-modes): Move alias before def, Noam Postavsky, 2019/12/22
- [elpa] master 1bee3a3 39/42: Fix #979: grok curly braces with LSP-style escaping, Noam Postavsky, 2019/12/22
- [elpa] master 3bf9a3b 41/42: Release 0.14.0, Noam Postavsky, 2019/12/22
- [elpa] master 4046f61 40/42: * yasnippet.el (yas-field-highlight-face): Remove redundant quote., Noam Postavsky, 2019/12/22
- [elpa] master 32f3512 42/42: * packages/yasnippet: Merge 0.14.0 from upstream., Noam Postavsky, 2019/12/22