mirror of
https://github.com/joaotavora/yasnippet.git
synced 2025-10-13 13:13:03 +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.
|
;; Assuming 2 space indent.
|
||||||
(should (string= "def xxx\n xxx\nend" (buffer-string)))))
|
(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 ()
|
(ert-deftest snippet-with-multiline-mirrors-issue-665 ()
|
||||||
"In issue 665, a multi-line mirror is attempted."
|
"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?
|
(= beg (yas--field-start field)) ; Insertion at field start?
|
||||||
(not (yas--field-modified-p field))))
|
(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)
|
(defun yas--on-field-overlay-modification (overlay after? beg end &optional length)
|
||||||
"Clears the field and updates mirrors, conditionally.
|
"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)))
|
(cl-assert (memq pfield (yas--snippet-fields psnippet)))
|
||||||
(yas--advance-end-maybe pfield (overlay-end overlay))
|
(yas--advance-end-maybe pfield (overlay-end overlay))
|
||||||
(setq pfield (yas--snippet-previous-active-field psnippet)))))
|
(setq pfield (yas--snippet-previous-active-field psnippet)))))
|
||||||
(save-excursion
|
;; Update fields now, but delay auto indentation until
|
||||||
(yas--field-update-display field))
|
;; post-command. We don't want to run indentation on
|
||||||
(yas--update-mirrors snippet)))
|
;; 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!")
|
(lwarn '(yasnippet zombie) :warning "Killing zombie snippet!")
|
||||||
(delete-overlay overlay)))))
|
(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 ()
|
(defun yas--auto-fill ()
|
||||||
(let* ((orig-point (point))
|
(let* ((orig-point (point))
|
||||||
(end (progn (forward-paragraph) (point)))
|
(end (progn (forward-paragraph) (point)))
|
||||||
@ -4800,46 +4820,58 @@ When multiple expressions are found, only the last one counts."
|
|||||||
(parent 1)
|
(parent 1)
|
||||||
(t 0))))))
|
(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)
|
(defun yas--update-mirrors (snippet)
|
||||||
"Update all the mirrors of SNIPPET."
|
"Update all the mirrors of SNIPPET."
|
||||||
(yas--save-restriction-and-widen
|
(yas--save-restriction-and-widen
|
||||||
(save-excursion
|
(save-excursion
|
||||||
(cl-loop
|
(let ((f-ms (yas--snippet-field-mirrors snippet)))
|
||||||
for (field . mirror)
|
(cl-loop
|
||||||
in (cl-sort
|
for (field . mirror) in f-ms
|
||||||
;; Make a list of (FIELD . MIRROR).
|
;; Before updating a mirror with a parent-field, maybe advance
|
||||||
(cl-mapcan (lambda (field)
|
;; its start (#290).
|
||||||
(mapcar (lambda (mirror)
|
do (let ((parent-field (yas--mirror-parent-field mirror)))
|
||||||
(cons field mirror))
|
(when parent-field
|
||||||
(yas--field-mirrors field)))
|
(yas--advance-start-maybe mirror (yas--fom-start parent-field))))
|
||||||
(yas--snippet-fields snippet))
|
;; Update this mirror.
|
||||||
;; Then sort this list so that entries with mirrors with
|
do (yas--mirror-update-display mirror field)
|
||||||
;; parent fields appear before. This was important for
|
;; `yas--place-overlays' is needed since the active field and
|
||||||
;; fixing #290, and also handles the case where a mirror in
|
;; protected overlays might have been changed because of insertions
|
||||||
;; a field causes another mirror to need reupdating.
|
;; in `yas--mirror-update-display'.
|
||||||
#'> :key (lambda (fm) (yas--calculate-mirror-depth (cdr fm))))
|
do (let ((active-field (yas--snippet-active-field snippet)))
|
||||||
;; Before updating a mirror with a parent-field, maybe advance
|
(when active-field (yas--place-overlays snippet active-field))))
|
||||||
;; its start (#290).
|
;; Delay indenting until we're done all mirrors. We must do
|
||||||
do (let ((parent-field (yas--mirror-parent-field mirror)))
|
;; this to avoid losing whitespace between fields that are
|
||||||
(when parent-field
|
;; still empty (i.e., they will be non-empty after updating).
|
||||||
(yas--advance-start-maybe mirror (yas--fom-start parent-field))))
|
(yas--indent-mirrors-of-snippet snippet f-ms)))))
|
||||||
;; 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)))))))
|
|
||||||
|
|
||||||
(defun yas--mirror-update-display (mirror field)
|
(defun yas--mirror-update-display (mirror field)
|
||||||
"Update MIRROR according to FIELD (and mirror transform)."
|
"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).
|
;; Don't pop up more than once in a session (still log though).
|
||||||
(defvar warning-suppress-types) ; `warnings' is autoloaded by `lwarn'.
|
(defvar warning-suppress-types) ; `warnings' is autoloaded by `lwarn'.
|
||||||
(add-to-list 'warning-suppress-types '(yasnippet auto-fill bug)))
|
(add-to-list 'warning-suppress-types '(yasnippet auto-fill bug)))
|
||||||
|
(yas--do-todo-field-updates)
|
||||||
(condition-case err
|
(condition-case err
|
||||||
(progn (yas--finish-moving-snippets)
|
(progn (yas--finish-moving-snippets)
|
||||||
(cond ((eq 'undo this-command)
|
(cond ((eq 'undo this-command)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user