(defvar cpc--backtrace nil "Backtrace of last error.") (defvar cpc--debugger-entries-count 0 "Backtrace of last error.") (defun cpc--handle-error (&rest args) "Handle an error in code run on the server. This function is appropriate as a value for `debugger' (hence ARGS). We need this function because the server doesn't print backtraces; thus we take a more aggressive stand and simply intercept all errors as they happen. We just store the backtrace in esh--server-backtrace and rethrow the error immediately; then the `condition-case' in `cpc-eval' will catch the error, unless it's nicely handled somewhere else." ;; Prevent recursive error catching (let ((debugger #'debug) (debug-on-quit nil) (debug-on-error nil) (debug-on-signal nil)) ;; HACK HACK HACK: this makes everything work fine ;;;;;;;;;;;;;;;;;; ;; (setq num-nonmacro-input-events (1+ num-nonmacro-input-events)) ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (setq cpc--debugger-entries-count (1+ cpc--debugger-entries-count)) (message "Debugger entered with args %S (%S times)" args cpc--debugger-entries-count) (pcase args (`(exit ,retv) retv) (`(error ,error-args) (setq cpc--backtrace (with-output-to-string (backtrace))) (signal (car error-args) (cdr error-args)))))) (defun cpc--writeout (file form) "Write FORM to FILE." (with-temp-buffer (insert (prin1-to-string form)) (write-region (point-min) (point-max) file))) (defun cpc-eval (form file) "Eval FORM and write result or error to FILE. Written value can be `read' from FILE; it is either a list (success RESULT) or a cons (error ERR BACKTRACE)." (message "Going to eval %S and write to %S" form file) (condition-case err (let* (;; Make sure that we'll intercept all errors (debug-on-quit t) (debug-on-error t) (debug-on-signal t) (debug-ignored-errors nil) ;; Make sure debugger has room to execute (max-specpdl-size (+ 50 max-specpdl-size)) (max-lisp-eval-depth (+ 50 max-lisp-eval-depth)) ;; Register ourselves as the debugger (debugger #'cpc--handle-error)) (setq cpc--backtrace nil) (cpc--writeout file `(success ,(eval form)))) (error (message "Condition-case entered with error %S" err) (cpc--writeout file `(error ,err ,cpc--backtrace))))) (defun cpc-messages () "Return contents of *Messages* buffer." (with-current-buffer "*Messages*" (buffer-string))) (provide 'cpc) ;;; cpc.el ends here