Rework error handling

* yasnippet.el (yas-good-grace): Add support for `inline' and `hooks' options.
(yas--eval-for-string): Renamed from `yas--eval-lisp'.  Errors are
passed straight through (no rethrow) when `yas-good-grace' is nil.
(yas--handle-error): Removed.
(yas--eval-for-effect): Renamed from `yas--eval-lisp-no-saves'.  Use
`yas--safely-run-hook'.
(yas-define-snippets): Update docstring.
(yas-throw): Don't throw, just signal.
(yas--save-backquotes, yas--apply-transform): Use
`yas--eval-for-string'.
(yas--safely-run-hook): Renamed from `yas--safely-run-hooks'.  Takes 1
hook function, instead of a hook var; check `yas-good-grace'.
(yas-expand-snippet): Use `yas--eval-for-effect'.
This commit is contained in:
João Távora 2016-05-18 06:32:18 -04:00 committed by Noam Postavsky
parent 9abf842e35
commit ac26024837

View File

@ -340,9 +340,16 @@ per-snippet basis. A value of `cua' is considered equivalent to
(const cua))) ; backwards compat (const cua))) ; backwards compat
(defcustom yas-good-grace t (defcustom yas-good-grace t
"If non-nil, don't raise errors in inline elisp evaluation. "If non-nil, don't raise errors in elisp evaluation.
An error string \"[yas] error\" is returned instead." This affects both the inline elisp in snippets and the hook
variables such as `yas-after-exit-snippet-hook'.
If this variable's value is `inline', an error string \"[yas]
error\" is returned instead of raising the error. If this
variable's value is `hooks', a message is output to according to
`yas-verbosity-level'. If this variable's value is t, both are
active."
:type 'boolean) :type 'boolean)
(defcustom yas-visit-from-menu nil (defcustom yas-visit-from-menu nil
@ -1323,33 +1330,27 @@ Returns (TEMPLATES START END). This function respects
;;; Internal functions and macros: ;;; Internal functions and macros:
(defun yas--handle-error (err) (defun yas--eval-for-string (form)
"Handle error depending on value of `yas-good-grace'."
(let ((msg (yas--format "elisp error: %s" (error-message-string err))))
(if yas-good-grace msg
(error "%s" msg))))
(defun yas--eval-lisp (form)
"Evaluate FORM and convert the result to string." "Evaluate FORM and convert the result to string."
(let ((retval (catch 'yas--exception (let ((eval-saving-stuff
(condition-case err (lambda (form)
(save-excursion (save-excursion
(save-restriction (save-restriction
(save-match-data (save-match-data
(widen) (widen)
(let ((result (eval form))) (let ((result (eval form)))
(when result (when result
(format "%s" result)))))) (format "%s" result)))))))))
(error (yas--handle-error err)))))) (if (memq yas-good-grace '(t inline))
(when (and (consp retval) (condition-case oops
(eq 'yas--exception (car retval))) (funcall eval-saving-stuff form)
(error (cdr retval))) (yas--exception (signal 'yas-exception (cdr oops)))
retval)) (error (cdr oops)))
(funcall eval-saving-stuff form))))
(defun yas--eval-lisp-no-saves (form) (defun yas--eval-for-effect (form)
(condition-case err ;; FIXME: simulating lexical-binding.
(eval form) (yas--safely-run-hook `(lambda () ,form)))
(error (message "%s" (yas--handle-error err)))))
(defun yas--read-lisp (string &optional nil-on-error) (defun yas--read-lisp (string &optional nil-on-error)
"Read STRING as a elisp expression and return it. "Read STRING as a elisp expression and return it.
@ -1665,7 +1666,7 @@ this is a snippet or a snippet-command.
CONDITION, EXPAND-ENV and KEYBINDING are Lisp forms, they have CONDITION, EXPAND-ENV and KEYBINDING are Lisp forms, they have
been `yas--read-lisp'-ed and will eventually be been `yas--read-lisp'-ed and will eventually be
`yas--eval-lisp'-ed. `yas--eval-for-string'-ed.
The remaining elements are strings. The remaining elements are strings.
@ -2855,7 +2856,8 @@ The last element of POSSIBILITIES may be a list of strings."
(defun yas-throw (text) (defun yas-throw (text)
"Throw a yas--exception with TEXT as the reason." "Throw a yas--exception with TEXT as the reason."
(throw 'yas--exception (cons 'yas--exception text))) (signal 'yas--exception text))
(put 'yas--exception 'error-conditions '(error yas--exception))
(defun yas-verify-value (possibilities) (defun yas-verify-value (possibilities)
"Verify that the current field value is in POSSIBILITIES. "Verify that the current field value is in POSSIBILITIES.
@ -3020,7 +3022,7 @@ string iff EMPTY-ON-NIL-P is true."
(transformed (and transform (transformed (and transform
(save-excursion (save-excursion
(goto-char start-point) (goto-char start-point)
(let ((ret (yas--eval-lisp transform))) (let ((ret (yas--eval-for-string transform)))
(or ret (and empty-on-nil-p ""))))))) (or ret (and empty-on-nil-p "")))))))
transformed)) transformed))
@ -3333,11 +3335,16 @@ This renders the snippet as ordinary text."
(yas--maybe-move-to-active-field snippet)) (yas--maybe-move-to-active-field snippet))
(setq yas--snippets-to-move nil)) (setq yas--snippets-to-move nil))
(defun yas--safely-run-hooks (hook-var) (defun yas--safely-run-hook (hook)
(condition-case error (let ((run-the-hook (lambda (hook) (funcall hook))))
(run-hooks hook-var) (if (memq yas-good-grace '(t hooks))
(error (funcall run-the-hook hook)
(yas--message 2 "%s error: %s" hook-var (error-message-string error))))) (condition-case error
(funcall run-the-hook hook)
(error
(yas--message 2 "Error running %s: %s"
(if (symbolp hook) hook "a hook")
(error-message-string error)))))))
(defun yas--check-commit-snippet () (defun yas--check-commit-snippet ()
@ -3371,8 +3378,8 @@ If so cleans up the whole snippet up."
nil))))) nil)))))
(unless (or (null snippets) snippets-left) (unless (or (null snippets) snippets-left)
(if snippet-exit-transform (if snippet-exit-transform
(yas--eval-lisp-no-saves snippet-exit-transform)) (yas--eval-for-effect snippet-exit-transform))
(yas--safely-run-hooks 'yas-after-exit-snippet-hook)))) (mapcar #'yas--safely-run-hook yas-after-exit-snippet-hook))))
;; Apropos markers-to-points: ;; Apropos markers-to-points:
;; ;;
@ -3648,7 +3655,7 @@ considered when expanding the snippet."
(cond ((listp content) (cond ((listp content)
;; x) This is a snippet-command ;; x) This is a snippet-command
;; ;;
(yas--eval-lisp-no-saves content)) (yas--eval-for-effect content))
(t (t
;; x) This is a snippet-snippet :-) ;; x) This is a snippet-snippet :-)
;; ;;
@ -4169,9 +4176,9 @@ with their evaluated value into `yas--backquote-markers-and-strings'."
(delete-region (match-beginning 0) (match-end 0))) (delete-region (match-beginning 0) (match-end 0)))
(let ((before-change-functions (let ((before-change-functions
(cons detect-change before-change-functions))) (cons detect-change before-change-functions)))
(setq transformed (yas--eval-lisp (yas--read-lisp (setq transformed (yas--eval-for-string (yas--read-lisp
(yas--restore-escapes (yas--restore-escapes
current-string '(?`)))))) current-string '(?`))))))
(goto-char (match-beginning 0)) (goto-char (match-beginning 0))
(when transformed (when transformed
(let ((marker (make-marker)) (let ((marker (make-marker))