add: nested fields and nested field skipping

This commit is contained in:
Joao Tavora 2013-10-20 13:41:32 +01:00
parent 5a067b8d3a
commit 478211060c
2 changed files with 76 additions and 8 deletions

View File

@ -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

View File

@ -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)))