mirror of
https://github.com/joaotavora/yasnippet.git
synced 2025-10-13 21:13:04 +00:00
add: nested fields and nested field skipping
This commit is contained in:
parent
5a067b8d3a
commit
478211060c
@ -36,6 +36,18 @@
|
||||
(contrived ((field 1)
|
||||
(field 2)
|
||||
(field 3)))
|
||||
(nested ("a "
|
||||
(field 1 ((field 2 "nested")
|
||||
" "
|
||||
(field 3 "field")))
|
||||
" and its mirror: "
|
||||
(mirror 1)))
|
||||
(mirror-of-nested-field ("a "
|
||||
(field 1 ((field 2 "nested")
|
||||
" "
|
||||
(field 3 "field")))
|
||||
(mirror 3 (concat ", nested mirroring: "
|
||||
field-text))))
|
||||
(printf ("printf (\""
|
||||
(field 1 "%s")
|
||||
(mirror 1 (if (string-match "%" field-text) "\"," "\")"))
|
||||
@ -99,6 +111,37 @@
|
||||
(ert-simulate-command '((lambda () (interactive) (insert "foo"))))
|
||||
(should (equal (buffer-string) "foobarbaz"))))
|
||||
|
||||
(ert-deftest nested-expansion ()
|
||||
(with-temp-buffer
|
||||
(snippet--insert-test-snippet 'nested)
|
||||
(should (equal (buffer-string) "a nested field and its mirror: nested field"))
|
||||
(ert-simulate-command '(snippet-next-field))
|
||||
(ert-simulate-command '((lambda () (interactive) (insert "nicely"))))
|
||||
(ert-simulate-command '(snippet-next-field))
|
||||
(ert-simulate-command '((lambda () (interactive) (insert "nested field"))))
|
||||
(should (equal (buffer-substring (overlay-start snippet--field-overlay)
|
||||
(overlay-end snippet--field-overlay))
|
||||
"nested field" ))
|
||||
(should (equal (buffer-string) "a nicely nested field and its mirror: nicely nested field"))))
|
||||
|
||||
(ert-deftest nested-skip-fields ()
|
||||
(with-temp-buffer
|
||||
(snippet--insert-test-snippet 'nested)
|
||||
(ert-simulate-command '((lambda () (interactive) (insert "foo"))))
|
||||
(should (equal (buffer-string) "a foo and its mirror: foo"))
|
||||
;; this should exit the snippet now, since the two remaining
|
||||
;; fields should be skipped
|
||||
(ert-simulate-command '(snippet-next-field))
|
||||
(should (null (overlay-buffer snippet--field-overlay)))))
|
||||
|
||||
(ert-deftest mirror-of-nested-field ()
|
||||
(with-temp-buffer
|
||||
(snippet--insert-test-snippet 'mirror-of-nested-field)
|
||||
(should (equal (buffer-string) "a nested field, nested mirroring: field"))
|
||||
(ert-simulate-command '(snippet-next-field))
|
||||
(ert-simulate-command '(snippet-next-field))
|
||||
(ert-simulate-command '((lambda () (interactive) (insert "foo"))))
|
||||
(should (equal (buffer-string) "a nested foo, nested mirroring: foo"))))
|
||||
|
||||
(ert-deftest printf-expansion ()
|
||||
(with-temp-buffer
|
||||
|
41
snippet.el
41
snippet.el
@ -409,17 +409,25 @@ can be:
|
||||
(defun snippet--object-next-field (object)
|
||||
(loop for next = (snippet--object-next object)
|
||||
then (snippet--object-next next)
|
||||
while next
|
||||
when (snippet--field-p next)
|
||||
while (and next)
|
||||
when (and (snippet--field-p next)
|
||||
(not (snippet--field-skip-p next)))
|
||||
return next))
|
||||
|
||||
(defun snippet--object-prev-field (object)
|
||||
(loop for prev = (snippet--object-prev object)
|
||||
then (snippet--object-prev prev)
|
||||
while prev
|
||||
when (snippet--field-p prev)
|
||||
when (and (snippet--field-p prev)
|
||||
(not (snippet--field-skip-p prev)))
|
||||
return prev))
|
||||
|
||||
(defun snippet--field-skip-p (field)
|
||||
(let ((parent (snippet--field-parent-field field)))
|
||||
(and parent
|
||||
(snippet--object-empty-p field)
|
||||
(snippet--field-modified-p parent))))
|
||||
|
||||
(defun snippet-next-field (&optional prev)
|
||||
(interactive)
|
||||
(let* ((field (overlay-get snippet--field-overlay 'snippet--field))
|
||||
@ -508,6 +516,11 @@ can be:
|
||||
(snippet--object-end field))
|
||||
(overlay-put snippet--field-overlay 'snippet--field field))
|
||||
|
||||
(defun snippet--update-field-mirrors (field)
|
||||
(mapc #'snippet--update-mirror (snippet--field-mirrors field))
|
||||
(when (snippet--object-parent-field field)
|
||||
(snippet--update-field-mirrors (snippet--object-parent-field field))))
|
||||
|
||||
(defun snippet--field-overlay-changed (overlay after? beg end
|
||||
&optional pre-change-len)
|
||||
;; there's a slight (apparently innocuous) bug here: if the overlay has
|
||||
@ -517,15 +530,27 @@ can be:
|
||||
(let* ((field (overlay-get overlay 'snippet--field))
|
||||
(inhibit-modification-hooks t))
|
||||
(cond (after?
|
||||
;; field clearing: if we're doing an insertion and the field hasn't
|
||||
;; been modified yet, we're going to delete previous contents and
|
||||
;; leave just the newly inserted text.
|
||||
;;
|
||||
(when (and (not (snippet--field-modified-p field))
|
||||
(= beg (snippet--field-start field))
|
||||
(zerop pre-change-len))
|
||||
(delete-region end
|
||||
(snippet--object-end field)))
|
||||
|
||||
;; At first glance, we could just delete the region between `end'
|
||||
;; and the `field's end, but that wouldn't empty any child fields
|
||||
;; that `field' might have, since that child's markers, albeit
|
||||
;; closed, may will have legitimately moved to accomodate the
|
||||
;; insertion. So we save the text, delete the entire field contents
|
||||
;; and insert it back in place. The child's markers will move
|
||||
;; together.
|
||||
;;
|
||||
(let ((saved (buffer-substring beg end)))
|
||||
(delete-region (snippet--object-start field)
|
||||
(snippet--object-end field))
|
||||
(insert saved)))
|
||||
(setf (snippet--field-modified-p field) t)
|
||||
|
||||
(mapc #'snippet--update-mirror (snippet--field-mirrors field))
|
||||
(snippet--update-field-mirrors field)
|
||||
(move-overlay overlay
|
||||
(snippet--object-start field)
|
||||
(snippet--object-end field)))
|
||||
|
Loading…
x
Reference in New Issue
Block a user