From 567ada01e6d0f150912055b1a2eadf2390ec44bd Mon Sep 17 00:00:00 2001 From: Noam Postavsky Date: Sat, 23 Apr 2016 16:36:10 -0400 Subject: [PATCH] Decide field clearing based on command's effect In [1] we started deciding clearing based on a command's delete-selection property, but it turns out that some commands perform insertion, and optionally use the region's contents. So these commands should have a nil delete-selection property, but they still ought to clear a snippet field when used. To achieve this, we now check if the command has inserted text in the post-change hook of the field overlay. * yasnippet.el (yas--skip-and-clear): Add optional FROM paramter. Only clear non-empty fields. (yas--skip-and-clear-field-p): Check the change start and length instead of current command delete-selection property. (yas--on-field-overlay-modification): Perform field clearing on the post-change call. [1]: acf2cdd "Decide field clearing commands based on delsel" --- yasnippet.el | 49 ++++++++++++++++++++++--------------------------- 1 file changed, 22 insertions(+), 27 deletions(-) diff --git a/yasnippet.el b/yasnippet.el index f91e130..24cb653 100644 --- a/yasnippet.el +++ b/yasnippet.el @@ -3348,15 +3348,17 @@ Otherwise deletes a character normally by calling `delete-char'." (t (call-interactively 'delete-char))))) -(defun yas--skip-and-clear (field) - "Deletes the region of FIELD and sets it's modified state to t." +(defun yas--skip-and-clear (field &optional from) + "Deletes the region of FIELD and sets it's modified state to t. +If given, FROM indicates position to start at instead of FIELD's beginning." ;; Just before skipping-and-clearing the field, mark its children ;; fields as modified, too. If the children have mirrors-in-fields ;; this prevents them from updating erroneously (we're skipping and ;; deleting!). ;; (yas--mark-this-and-children-modified field) - (delete-region (yas--field-start field) (yas--field-end field))) + (unless (= (yas--field-start field) (yas--field-end field)) + (delete-region (or from (yas--field-start field)) (yas--field-end field)))) (defun yas--mark-this-and-children-modified (field) (setf (yas--field-modified-p field) t) @@ -3390,40 +3392,33 @@ Move the overlay, or create it if it does not exit." (overlay-put yas--active-field-overlay 'insert-behind-hooks '(yas--on-field-overlay-modification)))) -(defun yas--skip-and-clear-field-p (field _beg _end &optional _length) +(defun yas--skip-and-clear-field-p (field beg _end length) "Tell if newly modified FIELD should be cleared and skipped. BEG, END and LENGTH like overlay modification hooks." - (and (not (yas--field-modified-p field)) - (= (point) (yas--field-start field)) - (require 'delsel) - ;; `yank' sets `this-command' to t during execution. - (let* ((command (if (commandp this-command) this-command - this-original-command)) - (clearp (if (symbolp command) (get command 'delete-selection)))) - (when (and (not (memq clearp '(yank supersede kill))) - (functionp clearp)) - (setq clearp (funcall clearp))) - clearp))) + (and (= length 0) ; A 0 pre-change length indicates insertion. + (= beg (yas--field-start field)) ; Insertion at field start? + (not (yas--field-modified-p field)))) -(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. Only clears the field if it hasn't been modified and point is at field start. This hook does nothing if an undo is in progress." - (unless (or yas--inhibit-overlay-hooks + (unless (or (not after?) + yas--inhibit-overlay-hooks (not (overlayp yas--active-field-overlay)) ; Avoid Emacs bug #21824. (yas--undo-in-progress)) - (let* ((field (overlay-get overlay 'yas--field)) + (let* ((inhibit-modification-hooks t) + (field (overlay-get overlay 'yas--field)) (snippet (overlay-get yas--active-field-overlay 'yas--snippet))) - (cond (after? - (yas--advance-end-maybe field (overlay-end overlay)) - (save-excursion - (yas--field-update-display field)) - (yas--update-mirrors snippet)) - (field - (when (yas--skip-and-clear-field-p field beg end) - (yas--skip-and-clear field)) - (setf (yas--field-modified-p field) t)))))) + (when (yas--skip-and-clear-field-p field beg end length) + ;; We delete text starting from the END of insertion. + (yas--skip-and-clear field end)) + (setf (yas--field-modified-p field) t) + (yas--advance-end-maybe field (overlay-end overlay)) + (save-excursion + (yas--field-update-display field)) + (yas--update-mirrors snippet)))) ;;; Apropos protection overlays: ;;