mirror of
https://github.com/joaotavora/yasnippet.git
synced 2025-10-15 05:53:04 +00:00
fix: properly handle snippet and mirror markers with `snippet--open-object'
* also snippet--close-object is apparently not needed * don't call the mirror transforms when field-text is null, just return empty string. also zero-length fields considered to have a null field-text, not the empty string. * correctly place markers when inserting objects
This commit is contained in:
parent
d43f42186d
commit
76bc40fd03
109
snippet.el
109
snippet.el
@ -215,8 +215,10 @@ I would need these somewhere in the let* form
|
|||||||
|
|
||||||
(defun snippet--transform-lambda (transform-form)
|
(defun snippet--transform-lambda (transform-form)
|
||||||
`(lambda (field-text)
|
`(lambda (field-text)
|
||||||
,(or transform-form
|
(if (null field-text)
|
||||||
'field-text)))
|
""
|
||||||
|
,(or transform-form
|
||||||
|
'field-text))))
|
||||||
|
|
||||||
(defun define--snippet-body (body)
|
(defun define--snippet-body (body)
|
||||||
"Does the actual work for `define-snippet'"
|
"Does the actual work for `define-snippet'"
|
||||||
@ -231,16 +233,24 @@ I would need these somewhere in the let* form
|
|||||||
|
|
||||||
,@(cl-loop
|
,@(cl-loop
|
||||||
for (sym form) in sym-tuples
|
for (sym form) in sym-tuples
|
||||||
collect (pcase form
|
append (pcase form
|
||||||
(`(field ,_ ,text)
|
(`(field ,_ . ,rest)
|
||||||
`(snippet--insert-field ,sym ,(if (stringp text)
|
`((snippet--insert-object ,sym)
|
||||||
text)))
|
,(when (stringp (car rest))
|
||||||
(`(mirror . ,_)
|
`(snippet--with-current-object ,sym
|
||||||
`(snippet--insert-mirror ,sym))
|
(insert ,(car rest))))))
|
||||||
((pred stringp)
|
(`(mirror . ,_)
|
||||||
`(insert ,form))
|
`((snippet--insert-object ,sym)))
|
||||||
((pred functionp)
|
((pred stringp)
|
||||||
`(insert (funcall ,form)))))
|
`((insert ,form)))
|
||||||
|
((pred functionp)
|
||||||
|
`((insert (funcall ,form))))))
|
||||||
|
,@(cl-loop
|
||||||
|
for (sym form) in sym-tuples
|
||||||
|
append (pcase form
|
||||||
|
(`(field . ,_)
|
||||||
|
`((mapc #'snippet--update-mirror
|
||||||
|
(snippet--field-mirrors ,sym))))))
|
||||||
|
|
||||||
(setq snippet--field-overlay
|
(setq snippet--field-overlay
|
||||||
(make-overlay (point) (point) nil nil t))
|
(make-overlay (point) (point) nil nil t))
|
||||||
@ -389,6 +399,7 @@ can be:
|
|||||||
(let ((map (make-sparse-keymap)))
|
(let ((map (make-sparse-keymap)))
|
||||||
(define-key map (kbd "<tab>") 'snippet-next-field)
|
(define-key map (kbd "<tab>") 'snippet-next-field)
|
||||||
(define-key map (kbd "S-<tab>") 'snippet-prev-field)
|
(define-key map (kbd "S-<tab>") 'snippet-prev-field)
|
||||||
|
(define-key map (kbd "<backtab>") 'snippet-prev-field)
|
||||||
map)
|
map)
|
||||||
"The active keymap while a snippet expansion is in progress.")
|
"The active keymap while a snippet expansion is in progress.")
|
||||||
|
|
||||||
@ -397,12 +408,14 @@ can be:
|
|||||||
(defun snippet--object-next-field (object)
|
(defun snippet--object-next-field (object)
|
||||||
(loop for next = (snippet--object-next object)
|
(loop for next = (snippet--object-next object)
|
||||||
then (snippet--object-next next)
|
then (snippet--object-next next)
|
||||||
|
while next
|
||||||
when (snippet--field-p next)
|
when (snippet--field-p next)
|
||||||
return next))
|
return next))
|
||||||
|
|
||||||
(defun snippet--object-prev-field (object)
|
(defun snippet--object-prev-field (object)
|
||||||
(loop for prev = (snippet--object-prev object)
|
(loop for prev = (snippet--object-prev object)
|
||||||
then (snippet--object-prev prev)
|
then (snippet--object-prev prev)
|
||||||
|
while prev
|
||||||
when (snippet--field-p prev)
|
when (snippet--field-p prev)
|
||||||
return prev))
|
return prev))
|
||||||
|
|
||||||
@ -430,43 +443,44 @@ can be:
|
|||||||
"")))
|
"")))
|
||||||
|
|
||||||
(defun snippet--make-marker ()
|
(defun snippet--make-marker ()
|
||||||
(let ((marker (make-marker)))
|
(point-marker))
|
||||||
(set-marker-insertion-type marker t)
|
|
||||||
(set-marker marker (point))))
|
|
||||||
|
|
||||||
(defun snippet--open-markers (object)
|
(defun snippet--object-empty-p (object)
|
||||||
|
(= (snippet--object-start object)
|
||||||
|
(snippet--object-end object)))
|
||||||
|
|
||||||
|
(defun snippet--objects-adjacent-p (prev next)
|
||||||
|
(eq (snippet--object-end prev)
|
||||||
|
(snippet--object-start next)))
|
||||||
|
|
||||||
|
(defun snippet--open-object (object)
|
||||||
(set-marker-insertion-type (snippet--object-start object) nil)
|
(set-marker-insertion-type (snippet--object-start object) nil)
|
||||||
(set-marker-insertion-type (snippet--object-end object) t))
|
(cl-loop for o = object then prev
|
||||||
|
for prev = (snippet--object-prev o)
|
||||||
|
while (and prev
|
||||||
|
(snippet--objects-adjacent-p prev o)
|
||||||
|
(snippet--object-empty-p prev))
|
||||||
|
do (set-marker-insertion-type (snippet--object-start prev) nil))
|
||||||
|
|
||||||
(defun snippet--close-markers (object)
|
(set-marker-insertion-type (snippet--object-end object) t)
|
||||||
(let ((start (snippet--object-start object))
|
(cl-loop for o = object then next
|
||||||
(end (snippet--object-end object)))
|
for next = (snippet--object-next o)
|
||||||
(cond ((= start end)
|
while (and next
|
||||||
(set-marker-insertion-type start t)
|
(snippet--objects-adjacent-p o next)
|
||||||
(set-marker-insertion-type end t))
|
(snippet--object-empty-p next))
|
||||||
(t
|
do (set-marker-insertion-type (snippet--object-end next) t)))
|
||||||
(set-marker-insertion-type start t)
|
|
||||||
(set-marker-insertion-type end nil)))))
|
|
||||||
|
|
||||||
(defun snippet--call-with-current-object (object fn)
|
(defun snippet--call-with-current-object (object fn)
|
||||||
(unwind-protect
|
(snippet--open-object object)
|
||||||
(progn
|
(funcall fn))
|
||||||
(snippet--open-markers object)
|
|
||||||
(funcall fn))
|
|
||||||
(snippet--close-markers object)))
|
|
||||||
|
|
||||||
(defmacro snippet--with-current-object (object &rest body)
|
(defmacro snippet--with-current-object (object &rest body)
|
||||||
(declare (indent defun) (debug t))
|
(declare (indent defun) (debug t))
|
||||||
`(snippet--call-with-current-object ,object #'(lambda () ,@body)))
|
`(snippet--call-with-current-object ,object #'(lambda () ,@body)))
|
||||||
|
|
||||||
|
(defun snippet--insert-object (object)
|
||||||
(defun snippet--insert-field (field text)
|
(set-marker (snippet--object-start object) (point))
|
||||||
(when text
|
(set-marker (snippet--object-end object) (point)))
|
||||||
(snippet--with-current-object field
|
|
||||||
(insert text))))
|
|
||||||
|
|
||||||
(defun snippet--insert-mirror (mirror)
|
|
||||||
(snippet--update-mirror mirror))
|
|
||||||
|
|
||||||
(defun snippet--update-mirror (mirror)
|
(defun snippet--update-mirror (mirror)
|
||||||
(snippet--with-current-object mirror
|
(snippet--with-current-object mirror
|
||||||
@ -484,24 +498,31 @@ can be:
|
|||||||
(snippet--object-end field))
|
(snippet--object-end field))
|
||||||
(overlay-put snippet--field-overlay 'snippet--field field))
|
(overlay-put snippet--field-overlay 'snippet--field field))
|
||||||
|
|
||||||
(defun snippet--field-overlay-changed (overlay after? _beg _end &optional _length)
|
(defun snippet--field-overlay-changed (overlay after? _beg _end
|
||||||
|
&optional _length)
|
||||||
|
;; there's a slight (apparently innocuous) bug here: if the overlay has
|
||||||
|
;; zero-length, both `insert-in-front' and `insert-behind' modification hooks
|
||||||
|
;; are called
|
||||||
|
;;
|
||||||
(let* ((field (overlay-get overlay 'snippet--field))
|
(let* ((field (overlay-get overlay 'snippet--field))
|
||||||
(inhibit-modification-hooks t))
|
(inhibit-modification-hooks t))
|
||||||
(cond (after?
|
(cond (after?
|
||||||
(snippet--close-markers field)
|
|
||||||
(mapc #'snippet--update-mirror (snippet--field-mirrors field))
|
(mapc #'snippet--update-mirror (snippet--field-mirrors field))
|
||||||
(move-overlay overlay
|
(move-overlay overlay
|
||||||
(snippet--object-start field)
|
(snippet--object-start field)
|
||||||
(snippet--object-end field)))
|
(snippet--object-end field)))
|
||||||
(t
|
(t
|
||||||
(snippet--open-markers field)))))
|
(snippet--open-object field)))))
|
||||||
|
|
||||||
(defun snippet--field-text (field)
|
(defun snippet--field-text (field)
|
||||||
(buffer-substring-no-properties (snippet--object-start field)
|
(let ((start (snippet--object-start field))
|
||||||
(snippet--object-end field)))
|
(end (snippet--object-end field)))
|
||||||
|
(and (/= start end)
|
||||||
|
(buffer-substring-no-properties start end))))
|
||||||
|
|
||||||
(defvar snippet--debug nil)
|
(defvar snippet--debug nil)
|
||||||
;; (setq snippet--debug t)
|
;; (setq snippet--debug t)
|
||||||
|
;; (setq snippet--debug nil)
|
||||||
|
|
||||||
(defun snippet--post-command-hook ()
|
(defun snippet--post-command-hook ()
|
||||||
(cond ((and snippet--field-overlay
|
(cond ((and snippet--field-overlay
|
||||||
|
Loading…
x
Reference in New Issue
Block a user