mirror of
https://github.com/joaotavora/yasnippet.git
synced 2025-10-13 05:03:04 +00:00
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.
This commit is contained in:
parent
6a738b581f
commit
ffce236268
@ -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."
|
||||
|
111
yasnippet.el
111
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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user