[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[elpa] master ffce236 30/42: Do auto indentation only in post command ho
From: |
Noam Postavsky |
Subject: |
[elpa] master ffce236 30/42: Do auto indentation only in post command hook |
Date: |
Sun, 22 Dec 2019 17:38:01 -0500 (EST) |
branch: master
commit ffce2362681d0bdaf096ed950e84e5f38a1149b4
Author: Noam Postavsky <address@hidden>
Commit: Noam Postavsky <address@hidden>
Do auto indentation only in post command hook
* yasnippet.el (yas--todo-snippet-indent): New variable.
(yas--on-field-overlay-modification): Save snippet to it, and don't
indent after mirror update.
(yas--do-todo-field-updates): New function.
(yas--post-command-handler): Call it.
(yas--snippet-field-mirrors, yas--indent-mirrors-of-snippet): New
functions, split out from...
(yas--snippet-field-mirrors): ...here.
* yasnippet-tests.el (yas-test-delete-and-insert-command)
(indent-mirrors-on-complex-update): New test and helper function.
---
yasnippet-tests.el | 22 +++++++++++
yasnippet.el | 111 ++++++++++++++++++++++++++++++++++-------------------
2 files changed, 94 insertions(+), 39 deletions(-)
diff --git a/yasnippet-tests.el b/yasnippet-tests.el
index c555a9e..db9c177 100644
--- a/yasnippet-tests.el
+++ b/yasnippet-tests.el
@@ -608,6 +608,28 @@ int foo()
;; Assuming 2 space indent.
(should (string= "def xxx\n xxx\nend" (buffer-string)))))
+(defun yas-test-delete-and-insert-command (beg end new)
+ "Simulate a completion command (similar to company-mode)."
+ (interactive "r\ns")
+ ;; Simulate a completion command (like what company-mode does)
+ ;; which deletes the "xxx" and then replaces it with something
+ ;; else.
+ (delete-region beg end)
+ (insert new))
+
+(ert-deftest indent-mirrors-on-complex-update ()
+ "Don't get messed up by command that deletes and then inserts."
+ (with-temp-buffer
+ (ruby-mode)
+ (yas-minor-mode 1)
+ (yas-expand-snippet "def foo\n ${1:slice} = append($1)\nend")
+ (yas-mock-insert "xxx")
+ (ert-simulate-command `(yas-test-delete-and-insert-command
+ ,(- (point) 3) ,(point) ,"yyy"))
+ ;; Assuming 2 space indent.
+ (should (string= "def foo\n yyy = append(yyy)\nend" (buffer-string)))))
+
+
(ert-deftest snippet-with-multiline-mirrors-issue-665 ()
"In issue 665, a multi-line mirror is attempted."
diff --git a/yasnippet.el b/yasnippet.el
index dcf593e..2ec192a 100644
--- a/yasnippet.el
+++ b/yasnippet.el
@@ -3785,6 +3785,9 @@ BEG, END and LENGTH like overlay modification hooks."
(= beg (yas--field-start field)) ; Insertion at field start?
(not (yas--field-modified-p field))))
+(defvar yas--todo-snippet-indent nil nil)
+(make-variable-buffer-local 'yas--todo-snippet-indent)
+
(defun yas--on-field-overlay-modification (overlay after? beg end &optional
length)
"Clears the field and updates mirrors, conditionally.
@@ -3819,12 +3822,29 @@ field start. This hook does nothing if an undo is in
progress."
(cl-assert (memq pfield (yas--snippet-fields psnippet)))
(yas--advance-end-maybe pfield (overlay-end overlay))
(setq pfield (yas--snippet-previous-active-field
psnippet)))))
- (save-excursion
- (yas--field-update-display field))
- (yas--update-mirrors snippet)))
+ ;; 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))))
(lwarn '(yasnippet zombie) :warning "Killing zombie snippet!")
(delete-overlay overlay)))))
+(defun yas--do-todo-field-updates ()
+ (when yas--todo-snippet-indent
+ (save-excursion
+ (cl-loop for snippet in yas--todo-snippet-indent
+ do (yas--indent-mirrors-of-snippet
+ snippet (yas--snippet-field-mirrors snippet)))
+ (setq yas--todo-snippet-indent nil))))
+
(defun yas--auto-fill ()
(let* ((orig-point (point))
(end (progn (forward-paragraph) (point)))
@@ -4800,46 +4820,58 @@ When multiple expressions are found, only the last one
counts."
(parent 1)
(t 0))))))
+(defun yas--snippet-field-mirrors (snippet)
+ ;; Make a list of (FIELD . MIRROR).
+ (cl-sort
+ (cl-mapcan (lambda (field)
+ (mapcar (lambda (mirror)
+ (cons field mirror))
+ (yas--field-mirrors field)))
+ (yas--snippet-fields snippet))
+ ;; Then sort this list so that entries with mirrors with
+ ;; parent fields appear before. This was important for
+ ;; fixing #290, and also handles the case where a mirror in
+ ;; a field causes another mirror to need reupdating.
+ #'> :key (lambda (fm) (yas--calculate-mirror-depth (cdr fm)))))
+
+(defun yas--indent-mirrors-of-snippet (snippet &optional f-ms)
+ ;; Indent mirrors of SNIPPET. F-MS is the return value of
+ ;; (yas--snippet-field-mirrors SNIPPET).
+ (when (eq yas-indent-line 'auto)
+ (let ((yas--inhibit-overlay-hooks t))
+ (cl-loop for (beg . end) in
+ (cl-sort (mapcar (lambda (f-m)
+ (let ((mirror (cdr f-m)))
+ (cons (yas--mirror-start mirror)
+ (yas--mirror-end mirror))))
+ (or f-ms
+ (yas--snippet-field-mirrors snippet)))
+ #'< :key #'car)
+ do (yas--indent-region beg end snippet)))))
+
(defun yas--update-mirrors (snippet)
"Update all the mirrors of SNIPPET."
(yas--save-restriction-and-widen
(save-excursion
- (cl-loop
- for (field . mirror)
- in (cl-sort
- ;; Make a list of (FIELD . MIRROR).
- (cl-mapcan (lambda (field)
- (mapcar (lambda (mirror)
- (cons field mirror))
- (yas--field-mirrors field)))
- (yas--snippet-fields snippet))
- ;; Then sort this list so that entries with mirrors with
- ;; parent fields appear before. This was important for
- ;; fixing #290, and also handles the case where a mirror in
- ;; a field causes another mirror to need reupdating.
- #'> :key (lambda (fm) (yas--calculate-mirror-depth (cdr fm))))
- ;; Before updating a mirror with a parent-field, maybe advance
- ;; its start (#290).
- do (let ((parent-field (yas--mirror-parent-field mirror)))
- (when parent-field
- (yas--advance-start-maybe mirror (yas--fom-start parent-field))))
- ;; Update this mirror.
- do (yas--mirror-update-display mirror field)
- ;; Delay indenting until we're done all mirrors. We must do
- ;; this to avoid losing whitespace between fields that are
- ;; still empty (i.e., they will be non-empty after updating).
- when (eq yas-indent-line 'auto)
- collect (cons (yas--mirror-start mirror) (yas--mirror-end mirror))
- into indent-regions
- ;; `yas--place-overlays' is needed since the active field and
- ;; protected overlays might have been changed because of insertions
- ;; in `yas--mirror-update-display'.
- do (let ((active-field (yas--snippet-active-field snippet)))
- (when active-field (yas--place-overlays snippet active-field)))
- finally do
- (let ((yas--inhibit-overlay-hooks t))
- (cl-loop for (beg . end) in (cl-sort indent-regions #'< :key #'car)
- do (yas--indent-region beg end snippet)))))))
+ (let ((f-ms (yas--snippet-field-mirrors snippet)))
+ (cl-loop
+ for (field . mirror) in f-ms
+ ;; Before updating a mirror with a parent-field, maybe advance
+ ;; its start (#290).
+ do (let ((parent-field (yas--mirror-parent-field mirror)))
+ (when parent-field
+ (yas--advance-start-maybe mirror (yas--fom-start
parent-field))))
+ ;; Update this mirror.
+ do (yas--mirror-update-display mirror field)
+ ;; `yas--place-overlays' is needed since the active field and
+ ;; protected overlays might have been changed because of insertions
+ ;; in `yas--mirror-update-display'.
+ do (let ((active-field (yas--snippet-active-field snippet)))
+ (when active-field (yas--place-overlays snippet active-field))))
+ ;; Delay indenting until we're done all mirrors. We must do
+ ;; this to avoid losing whitespace between fields that are
+ ;; still empty (i.e., they will be non-empty after updating).
+ (yas--indent-mirrors-of-snippet snippet f-ms)))))
(defun yas--mirror-update-display (mirror field)
"Update MIRROR according to FIELD (and mirror transform)."
@@ -4897,6 +4929,7 @@ When multiple expressions are found, only the last one
counts."
;; Don't pop up more than once in a session (still log though).
(defvar warning-suppress-types) ; `warnings' is autoloaded by `lwarn'.
(add-to-list 'warning-suppress-types '(yasnippet auto-fill bug)))
+ (yas--do-todo-field-updates)
(condition-case err
(progn (yas--finish-moving-snippets)
(cond ((eq 'undo this-command)
- [elpa] master dabc719 21/42: Don't turn on yas-minor-mode in temp buffers, (continued)
- [elpa] master dabc719 21/42: Don't turn on yas-minor-mode in temp buffers, Noam Postavsky, 2019/12/22
- [elpa] master fc33b2f 28/42: Make overlay-modification protection optional, Noam Postavsky, 2019/12/22
- [elpa] master 048d030 22/42: Fix line-relative snapshotting for org src blocks, Noam Postavsky, 2019/12/22
- [elpa] master bae20af 27/42: ; * doc/faq.org: Linkify bug reference., Noam Postavsky, 2019/12/22
- [elpa] master ffc733d 09/42: ; Debug code fixes, Noam Postavsky, 2019/12/22
- [elpa] master 1d96da2 18/42: Don't call before/after change-functions twice, Noam Postavsky, 2019/12/22
- [elpa] master 6a3619b 23/42: Fix additional corner case with org source block integration, Noam Postavsky, 2019/12/22
- [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 <=
- [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, 2019/12/22
- [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