From ee4efdbbde2da236fa06bb18290339d0cdca6699 Mon Sep 17 00:00:00 2001 From: Noam Postavsky Date: Tue, 21 Jun 2016 21:27:27 -0400 Subject: [PATCH 1/2] Revert "Separate parsing from evaluation of backquote lisp" This reverts commit e21420a497c1d79edc6b36ffb1f3bf1bb70f6227. This breaks existing snippets which use side-effecting functions inside backquotes to insert data instead of return the string to insert. This usage will be deprecated, but we still need to support it for at least another release. * yasnippet.el (yas--save-backquotes): Go back to interleaved parsing and evaluating of backquoted lisp forms. --- yasnippet.el | 42 ++++++++++++++---------------------------- 1 file changed, 14 insertions(+), 28 deletions(-) diff --git a/yasnippet.el b/yasnippet.el index 5164754..8a6258c 100644 --- a/yasnippet.el +++ b/yasnippet.el @@ -4017,34 +4017,20 @@ With optional string TEXT do it in string instead of the buffer." (defun yas--save-backquotes () "Save all the \"`(lisp-expression)`\"-style expressions with their evaluated value into `yas--backquote-markers-and-strings'." - ;; Gather `(lisp-expression)`s. - (let ((end (point-max))) - (save-restriction - (widen) - (while (re-search-forward yas--backquote-lisp-expression-regexp end t) - (let ((expr (yas--read-lisp (yas--restore-escapes - (match-string-no-properties 1)))) - (marker (make-marker))) - (delete-region (match-beginning 0) (match-end 0)) - (insert "Y") ;; quite horrendous, I love it :) - (set-marker marker (point)) - (insert "Y") - (push (cons marker expr) yas--backquote-markers-and-strings))))) - ;; Evaluate them. - (dolist (m-e yas--backquote-markers-and-strings) - (let* ((marker (car m-e)) - (expr (cdr m-e)) - (result (save-excursion - (goto-char marker) - (yas--eval-lisp expr)))) - (setcdr m-e result) - (unless result - (save-restriction (widen) - (delete-region (1- marker) (1+ marker))) - (set-marker marker nil)))) - ;; Drop the nil results. - (setq yas--backquote-markers-and-strings - (cl-delete-if-not #'cdr yas--backquote-markers-and-strings))) + (while (re-search-forward yas--backquote-lisp-expression-regexp nil t) + (let ((current-string (match-string-no-properties 1)) transformed) + (save-restriction (widen) + (delete-region (match-beginning 0) (match-end 0))) + (setq transformed (yas--eval-lisp (yas--read-lisp (yas--restore-escapes current-string '(?`))))) + (goto-char (match-beginning 0)) + (when transformed + (let ((marker (make-marker))) + (save-restriction + (widen) + (insert "Y") ;; quite horrendous, I love it :) + (set-marker marker (point)) + (insert "Y")) + (push (cons marker transformed) yas--backquote-markers-and-strings)))))) (defun yas--restore-backquotes () "Replace markers in `yas--backquote-markers-and-strings' with their values." From 85f39cec2b0e34f60266057f5ef2f45193d75339 Mon Sep 17 00:00:00 2001 From: Noam Postavsky Date: Tue, 21 Jun 2016 22:06:30 -0400 Subject: [PATCH 2/2] Warn about backquote exprs modifying the buffer * yasnippet.el (yas--save-backquotes): Show a warning if evaluating the backquote expression modifies the buffer. --- yasnippet.el | 41 +++++++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/yasnippet.el b/yasnippet.el index 8a6258c..406b514 100644 --- a/yasnippet.el +++ b/yasnippet.el @@ -4017,20 +4017,33 @@ With optional string TEXT do it in string instead of the buffer." (defun yas--save-backquotes () "Save all the \"`(lisp-expression)`\"-style expressions with their evaluated value into `yas--backquote-markers-and-strings'." - (while (re-search-forward yas--backquote-lisp-expression-regexp nil t) - (let ((current-string (match-string-no-properties 1)) transformed) - (save-restriction (widen) - (delete-region (match-beginning 0) (match-end 0))) - (setq transformed (yas--eval-lisp (yas--read-lisp (yas--restore-escapes current-string '(?`))))) - (goto-char (match-beginning 0)) - (when transformed - (let ((marker (make-marker))) - (save-restriction - (widen) - (insert "Y") ;; quite horrendous, I love it :) - (set-marker marker (point)) - (insert "Y")) - (push (cons marker transformed) yas--backquote-markers-and-strings)))))) + (let* ((yas--change-detected nil) + (detect-change (lambda (_beg _end) (setq yas--change-detected t)))) + (while (re-search-forward yas--backquote-lisp-expression-regexp nil t) + (let ((current-string (match-string-no-properties 1)) transformed) + (save-restriction (widen) + (delete-region (match-beginning 0) (match-end 0))) + (let ((before-change-functions + (cons detect-change before-change-functions))) + (setq transformed (yas--eval-lisp (yas--read-lisp + (yas--restore-escapes + current-string '(?`)))))) + (goto-char (match-beginning 0)) + (when transformed + (let ((marker (make-marker)) + (before-change-functions (cdr before-change-functions))) + (save-restriction + (widen) + (insert "Y") ;; quite horrendous, I love it :) + (set-marker marker (point)) + (insert "Y")) + (push (cons marker transformed) yas--backquote-markers-and-strings))))) + (when yas--change-detected + (lwarn '(yasnippet backquote-change) :warning + "`%s' modified buffer in a backquote expression." + (if yas--current-template + (yas--template-name yas--current-template) + "Snippet"))))) (defun yas--restore-backquotes () "Replace markers in `yas--backquote-markers-and-strings' with their values."