Fix whitespace lossage between mirrors

* yasnippet.el (yas--update-mirrors): Delay indentation until all
mirrors are updated.
(yas--mirror-update-display): Don't indent here.
* yasnippet-tests.el (single-line-multi-mirror-indentation-2): New test.
This commit is contained in:
Noam Postavsky 2017-01-28 00:28:57 -05:00
parent 0041efedf9
commit e74f00e703
2 changed files with 47 additions and 44 deletions

View File

@ -244,6 +244,16 @@ $1 ------------------------")
XXXXX ---------------- XXXXX ---- XXXXX ---------------- XXXXX ----
XXXXX ------------------------")))) XXXXX ------------------------"))))
(ert-deftest single-line-multi-mirror-indentation-2 ()
"Like `single-line-multi-mirror-indentation' but 2 mirrors interleaved."
;; See also Github issue #768.
(with-temp-buffer
(c-mode)
(yas-minor-mode 1)
(yas-expand-snippet "${1:one} ${2:two};\n$1 $2_;\n$2 $1_;\n")
(should (string= (yas--buffer-contents)
"one two;\none two_;\ntwo one_;\n"))))
(ert-deftest indent-org-property () (ert-deftest indent-org-property ()
"Handling of `org-mode' property indentation, see `org-property-format'." "Handling of `org-mode' property indentation, see `org-property-format'."
;; This is an interesting case because `org-indent-line' calls ;; This is an interesting case because `org-indent-line' calls

View File

@ -4365,44 +4365,42 @@ When multiple expressions are found, only the last one counts."
(save-restriction (save-restriction
(widen) (widen)
(save-excursion (save-excursion
(dolist (field-and-mirror (cl-loop
(sort for (field . mirror)
;; make a list of ((F1 . M1) (F1 . M2) (F2 . M3) (F2 . M4) ...) in (cl-sort
;; where F is the field that M is mirroring ;; Make a list of (FIELD . MIRROR).
;; (cl-mapcan (lambda (field)
(cl-mapcan #'(lambda (field) (mapcar (lambda (mirror)
(mapcar #'(lambda (mirror)
(cons field mirror)) (cons field mirror))
(cl-sort (yas--field-mirrors field)))
(cl-copy-list
(yas--field-mirrors field))
#'<
:key #'yas--mirror-start)))
(yas--snippet-fields snippet)) (yas--snippet-fields snippet))
;; then sort this list so that entries with mirrors with parent ;; Then sort this list so that entries with mirrors with
;; fields appear before. This was important for fixing #290, and ;; parent fields appear before. This was important for
;; luckily also handles the case where a mirror in a field causes ;; fixing #290, and also handles the case where a mirror in
;; another mirror to need reupdating ;; a field causes another mirror to need reupdating.
;; #'> :key (lambda (fm) (yas--calculate-mirror-depth (cdr fm))))
#'(lambda (field-and-mirror1 field-and-mirror2) ;; Before updating a mirror with a parent-field, maybe advance
(> (yas--calculate-mirror-depth (cdr field-and-mirror1)) ;; its start (#290).
(yas--calculate-mirror-depth (cdr field-and-mirror2)))))) do (let ((parent-field (yas--mirror-parent-field mirror)))
(let* ((field (car field-and-mirror))
(mirror (cdr field-and-mirror))
(parent-field (yas--mirror-parent-field mirror)))
;; before updating a mirror with a parent-field, maybe advance
;; its start (#290)
;;
(when parent-field (when parent-field
(yas--advance-start-maybe mirror (yas--fom-start parent-field))) (yas--advance-start-maybe mirror (yas--fom-start parent-field))))
;; update this mirror ;; Update this mirror.
;; do (yas--mirror-update-display mirror field snippet)
(yas--mirror-update-display mirror field snippet) ;; 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 ;; `yas--place-overlays' is needed since the active field and
;; protected overlays might have been changed because of insertions ;; protected overlays might have been changed because of insertions
;; in `yas--mirror-update-display'. ;; in `yas--mirror-update-display'.
(let ((active-field (yas--snippet-active-field snippet))) do (let ((active-field (yas--snippet-active-field snippet)))
(when active-field (yas--place-overlays snippet active-field)))))))) (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)))))))
(defun yas--mirror-update-display (mirror field snippet) (defun yas--mirror-update-display (mirror field snippet)
"Update MIRROR according to FIELD (and mirror transform)." "Update MIRROR according to FIELD (and mirror transform)."
@ -4423,12 +4421,7 @@ When multiple expressions are found, only the last one counts."
(set-marker (yas--mirror-end mirror) (point)) (set-marker (yas--mirror-end mirror) (point))
(yas--advance-start-maybe (yas--mirror-next mirror) (point)) (yas--advance-start-maybe (yas--mirror-next mirror) (point))
;; super-special advance ;; super-special advance
(yas--advance-end-of-parents-maybe mirror-parent-field (point))) (yas--advance-end-of-parents-maybe mirror-parent-field (point))))))
(when (eq yas-indent-line 'auto)
(let ((yas--inhibit-overlay-hooks t))
(yas--indent-region (yas--mirror-start mirror)
(yas--mirror-end mirror)
snippet))))))
(defun yas--field-update-display (field) (defun yas--field-update-display (field)
"Much like `yas--mirror-update-display', but for fields." "Much like `yas--mirror-update-display', but for fields."